SWEA 1238 - 무선 충전

Updated:

Java

1238 번 - 무선 충전

문제

BC의 정보와 사용자의 이동 궤적이 주어졌을 때, 모든 사용자가 충전한 양의 합의 최댓값을 구하는 프로그램을 작성하라.

접근 방법

꽤 복잡한 구현 문제였다.

각 배터리마다 범위를 표현하기 위해 3차원 배열을 사용하였다.
첫번째 인덱스는 각 배터리를 나타내고, 두번째/세번째 인덱스는 y,x값을 두어, 각 배터리마다 충전할 수 있는 범위를 나타내었다.

이제 A와 B가 각 시간마다 동시에 움직이게 하였다.
정해진 경로를 통해 한칸씩 움직이며, 각 좌표에 도달할 때 위치에서 배터리의 범위에 들어올 수 있으면 현재 배터리의 정보를 List에 저장한다.

이후 A와 B 마다 현재 충전 할 수있는 배터리의 정보가 들어있는 List의 배터리 값을 더해보며, 그 중 가장 세기가 큰 배터리의 합 값을 충전한다.

코드

import java.io.*;
import java.util.*;

class Solution {
	static int result = 0;
	static int[][][] map;
	public static void main(String []args) throws Exception {  
    	BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    	StringTokenizer stk;
    	int tc = stoi(br.readLine());
    	
    	for(int tidx = 1; tidx <= tc; tidx++) {
    		result = 0;
    		int M, A;
    		stk = new StringTokenizer(br.readLine());
    		M = stoi(stk.nextToken());
    		A = stoi(stk.nextToken());
    		int[] aMove = new int[M + 1];
    		int[] bMove = new int[M + 1];
    		// A의 이동
    		stk = new StringTokenizer(br.readLine());
    		for(int i = 1; i <= M; i++) {
    			aMove[i] = stoi(stk.nextToken());
    		}
    		// B의 이동
    		stk = new StringTokenizer(br.readLine());
    		for(int i = 1; i <= M; i++) {
    			bMove[i] = stoi(stk.nextToken());
    		}
    		// 배터리의 범위를 설정한다.
    		map = new int[A + 1][11][11];
    		int[] bcValue = new int[A + 1];
    		for(int i = 1; i <= A; i++) {
    			stk = new StringTokenizer(br.readLine());
    			MakeBC(i, stoi(stk.nextToken()), stoi(stk.nextToken()), stoi(stk.nextToken()));
    			bcValue[i] = stoi(stk.nextToken());	 // BC의 세기
    		}
    		List<Integer> aBC = new ArrayList<Integer>();
    		List<Integer> bBC = new ArrayList<Integer>();
    		int ay = 1, ax = 1;		// A의 현재 좌표 
    		int by = 10, bx = 10;
    		
    		// 시간의 흐름
    		for(int t = 0; t <= M; t++) {
    			
    			ay += dy[aMove[t]];
    			ax += dx[aMove[t]];
    			by += dy[bMove[t]];
    			bx += dx[bMove[t]];
    			
    			aBC.clear();
    			bBC.clear();
    			
        		for(int i = 1; i <= A; i++) {
        			if(map[i][ay][ax] != 0) {
        				aBC.add(i);
        			}
        			if(map[i][by][bx] != 0) {
        				bBC.add(i);
        			}
        		}
    			
        		Collections.sort(bBC, (o1, o2)->{return -Integer.compare(bcValue[o1], bcValue[o2]);});
        		Collections.sort(aBC, (o1, o2)->{return -Integer.compare(bcValue[o1], bcValue[o2]);});
        		// 현재 B만 배터리 범위에 있는 경우
        		if(aBC.isEmpty() && !bBC.isEmpty()) {
        			result += bcValue[bBC.get(0)];
        		}
				// A만 배터리 범위에 있는 경우
        		else if(!aBC.isEmpty() && bBC.isEmpty()) {
        			result += bcValue[aBC.get(0)];
        		}
				// A,B 둘 다 배터리 범위에 있는 경우
        		else if(!aBC.isEmpty() && !bBC.isEmpty()){
        			int max = 0;
        			int sum = 0;
        			int curA, curB;
					// 현재 충전 할 수 있는 배터리 값의 합을 구하여 그 중 최대를 구한다.
        			for(int i = 0; i < aBC.size(); i++) {
            			for(int j = 0; j < bBC.size(); j++) {
            				curA = aBC.get(i);
            				curB = bBC.get(j);
            				if(curA == curB) {
            					max = Math.max(max, bcValue[curA]);
            				}
            				else {
            					sum = bcValue[curA] + bcValue[curB];
            					max = Math.max(max, sum);
            				}
            			}
        			}
        			result += max;
        		}
    		}	
    		System.out.println("#" + tidx + " " + result);
    	}
	}
	
	static int[] dy = {0, -1, 0, 1, 0};
	static int[] dx = {0, 0, 1, 0, -1};
	
	// 배터리 충전 범위들을 만들어 준다.  
	static void MakeBC(int idx, int x, int y, int time) {
		map[idx][y][x] = 1;
		
		Queue<Point> queue = new LinkedList<>();
		queue.add(new Point(y,x));
		
		int t = 0, cnt = 1, loop;
		int ny,nx;
		Point p;
		while(t < time) {			
			loop = cnt;
			cnt = 0;
			for(int k = 0; k < loop; k++) {
				p = queue.poll();
				y = p.y;
				x = p.x;
				for(int i = 1; i <= 4; i++) {
					ny = y + dy[i];
					nx = x + dx[i];
					
					if(isIn(ny,nx) && map[idx][ny][nx] == 0) {
						map[idx][ny][nx] = 1;
						queue.add(new Point(ny,nx));
						cnt++;
					}
				}
			}
			t++;
		}
	}
	
	// 주어진 범위 안에 있는가
    public static boolean isIn(int y, int x){
        if(y == 0 || y >= 11 || x == 0 || x >= 11)
            return false;
        return true;
    }
    
    static class Point {
    	int y, x;

		public Point(int y, int x) {
			super();
			this.y = y;
			this.x = x;
		}
    }
	
	static int stoi(String str) {
    	return Integer.parseInt(str);
    }
}

총평

후기

좀 많이 꼬여서 복잡하게 푼 문제였다.

개선할 점

굳이 BFS로 미리 배터리 범위를 구할 필요 없이, 각 점마다 모든 배터리 위치를 비교하여([y1 - y2] + [x1 - x2]) 범위 내에 있는지만 확인하면 된다.