https://swexpertacademy.com/main/code/problem/problemDetail.do?contestProbId=AWXRDL1aeugDFAUo
문제 요약 정리
최적의 BC를 선택하기
행과 열이 바뀌어있는 문제
단, BC 1과 BC 3의 충전 범위에 모두 속하기 때문에,
이 위치에서는 두 BC 중 하나를 선택하여 접속할 수 있다.
1. 이동 가능 범위 구하기 -> bfs
bfs 깊이1 == C가 1일때
bfs 깊이2 = C가 2일때
2. 배터리 충전
매초마다 특정 BC의 충전 범위에 안에 들어오면 해당 BC에 접속이 가능
접속한 BC의 성능만큼 배터리 충전이 가능하다.
단, 두명의 접속자가 1개의 BC에 접속한 경우, 각각 충전양/사용자수 만큼 충전해준다.
같은 구역내에 있다 ==
모두 범위 밖일경우 -> 아무런 작업 x
A만 범위에 있는 경우 -> 최댓값 +
B만 범위에 있는 경우 -> 최댓값 +
A,B 모두 범위에 있는 경우 -> A랑 B가 같은 위치에 있을 경우
무조건 큰 값 선택하기
A 선택 가능 : 1(500), 2(200)
B 선택 가능 : 1(500)
A 선택 가능 : 1(200), 2(500)
B 선택 가능 : 1(200)
10<=P<=500
500 10, 500
같은 위치에 도착했을 때
-> (1) (10,500) ==> 510
-> (2) (500,500) -> 250+250 == 500
1번이 더 효과적이다.
3. 모든 사용자가 충전한 양의 합의 최댓값을 구하라.
※ 제약 조건 ※
사용자 A는 BC 1과 3 둘 중 하나에 접속이 가능하다. 같은 시간에 사용자 B는 BC 1에 접속할 수 밖에 없다
문제 접근 방식
1. bfs로 무전기의 영역을 체크한다.
2. 사용자 A와 사용자 B를 동시에 움직이면서
충전한 양의 합의 최댓값 구하기 --> move() 함수 참고
시행 착오
1. dfs -> bfs로 변경함
: dfs로 풀다가 bfs로 변경했는데,
dfs로도 풀 수 있는 문제임에도 풀지 못했다 ㅠ.ㅠ
주말에 dfs로 다시 풀어보기
2. A와 B가 모두 같은 범위에 있을때의 조건을
무전기 번호로 해야하는데
처음에 구현할 땐 c(범위), p(충전 처리량)이 같으면
같은 범위라고 인정해줘서
테케 50개 중에 49개만 맞는 불상사가 일어남..
A,B가 모두 같은 범위 내에 있을때
최댓값을 구해주는 문제는
for문을 돌리면 되는 문제였다
(쏘씸플했던 부분..이었지만 나에겐 쏘하드했음)
소스 코드
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 | import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Queue; import java.util.StringTokenizer; public class Solution { static ArrayList<Battery>[][] map; static final int N=10; static int[][] teamA; // A의 위치 static int[][] teamB; // B의 위치 static int[] dxs= {0,-1,0,1,0}; // 상,우,하,좌 static int[] dys= {0,0,1,0,-1}; static int[] moveA; static int[] moveB; static boolean[][] visited; static int M; // 이동 시간 static int C; // 충전 범위 static int P; // 처리량 static int answer; static class Battery implements Comparable<Battery>{ int x, y, c, p,no; public Battery(int x, int y, int c, int p,int no) { super(); this.x = x; this.y = y; this.c = c; this.p = p; this.no=no; } @Override public int compareTo(Battery o) { return this.p!=o.p ? o.p-this.p :this.p-o.p; // 충전량 기준으로 내림차순 정렬 } } public static boolean can_go(int x,int y) { return x>0 && x<=N && y>0 && y<=N && !visited[x][y]; } // AP 범위 체크하는 함수 public static void bfs(int depth, int x, int y, int no) { // no == 무전기 번호 Queue<int[]> queue= new ArrayDeque<>(); // 자료형 배열로 변경 queue.offer(new int[]{x,y,0,no}); visited[x][y]=true; // 해당 칸 방문처리 while(queue.size()!=0) { int[] curArr=queue.poll(); int cx=curArr[0]; // 현재 x 좌표 int cy=curArr[1]; // 현재 y 좌표 int cnt=curArr[2]; // 현재 깊이 visited[cx][cy]=true; if (cnt< C) { for (int i = 1; i <5; i++) { int nx=cx+dxs[i]; int ny=cy+dys[i]; if (can_go(nx,ny)) { if (map[nx][ny]==null) { // 아무런 수가 채워져있지 않은 경우 map[nx][ny] = new ArrayList<Battery>(); } map[nx][ny].add(new Battery(nx, ny,C,P,no)); // 충전 범위, 충전량 queue.offer(new int[] {nx,ny,cnt+1}); } } } } } // A,B 움직이기 public static void move(int aX, int aY, int bX, int bY) { // 시작점 계산 // A의 현재 위치 int temp=Integer.MIN_VALUE; if (map[aX][aY]!=null) { if(map[bX][bY]!=null) { // A,B 모두 범위에 있는 경우 for (Battery bA : map[aX][aY]) { for (Battery bB : map[bX][bY]) { if(bA.no==bB.no && bA.p==bB.p) { temp=Math.max(temp, bA.p); }else { temp=Math.max(temp,bA.p+bB.p); } } } }else { // A만 범위에 있는 경우 -> 최댓값 + for (Battery bA : map[aX][aY]) { temp=Math.max(temp,bA.p); } } }else { if(map[bX][bY]!=null) { // B만 범위에 있는 경우 -> 최댓값 + for (Battery bB : map[bX][bY]) { temp=Math.max(temp,bB.p); } } // 모두 범위 밖일경우 -> 아무런 작업 x else{ temp=0; } } answer+=temp; } public static void main(String[] args) throws IOException { BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); int T=Integer.parseInt(br.readLine()); for (int t = 1; t <= T; t++) { answer=0; teamA=new int[1][2]; teamB=new int[1][2]; teamA[0][0]=1; teamA[0][1]=1; teamB[0][0]=N; teamB[0][1]=N; map=new ArrayList[N+1][N+1]; // 가로, 세로 크기는 10 (맵 정보 배열) StringTokenizer st = new StringTokenizer(br.readLine()); M=Integer.parseInt(st.nextToken()); // 총 이동시간 int A=Integer.parseInt(st.nextToken()); // BC의 개수 moveA=new int[M]; moveB=new int[M]; st = new StringTokenizer(br.readLine()); // A의 이동정보 for (int i = 0; i < M; i++) { moveA[i]=Integer.parseInt(st.nextToken()); } // B의 이동정보 st = new StringTokenizer(br.readLine()); for (int i = 0; i < M; i++) { moveB[i]=Integer.parseInt(st.nextToken()); } // AP의 위치정보(x,y), 충전 범위(C), 처리량(P) for (int i = 0; i < A; i++) { visited=new boolean[N+1][N+1]; // 가로, 세로 크기는 10 (방문 체크 배열) st = new StringTokenizer(br.readLine()); int Y= Integer.parseInt(st.nextToken()); int X=Integer.parseInt(st.nextToken()); C=Integer.parseInt(st.nextToken()); // 충전범위 = 깊이 P=Integer.parseInt(st.nextToken()); // 처리량 = 배터리 충전량 if (map[X][Y]==null) { map[X][Y]=new ArrayList<>(); } map[X][Y].add(new Battery(X, Y, C, P, i+1)); // 충전범위, 충전량, 무전기 번호 bfs(0,X,Y,i+1); } int aX = teamA[0][0]; int aY = teamA[0][1]; // B의 현재 위치 int bX = teamB[0][0]; int bY = teamB[0][1]; move(aX,aY,bX,bY); // 초기위치 값 갱신 for (int i = 0; i < M; i++) { int direcA=moveA[i]; int direcB=moveB[i]; // A 이동위치 aX=aX+dxs[direcA]; aY=aY+dys[direcA]; // B 이동위치 bX=bX+dxs[direcB]; bY=bY+dys[direcB]; move(aX,aY,bX,bY); } System.out.println("#"+t+" "+ answer); } } } | cs |
'여니의 취준 준비 > 코딩테스트 (Java)' 카테고리의 다른 글
[*3109*] 빵집 in Java ( + Backtracking, DFS ) (0) | 2022.08.18 |
---|---|
[*1992*] 쿼드트리 in Java (0) | 2022.08.18 |
[*1828*] 냉장고 in Java (feat. 정올, Comparator, Comparable 차이 및 설명) (0) | 2022.08.16 |
[20207] 달력 in Java (0) | 2022.08.14 |
[17471] 게리맨더링 in Java (0) | 2022.08.14 |