'PS'에 해당되는 글 131건

  1. 2022.05.20 5648 원자소멸 시뮬레이션
  2. 2022.05.20 5650 핀볼게임
  3. 2022.05.17 5656 벽돌깨기
  4. 2022.05.16 5658 보물상자 비밀번호
  5. 2022.05.16 5644 무선 충전
  6. 2022.05.15 4014 활주로 탐색
  7. 2022.05.15 4013 특이한 자석
  8. 2022.05.15 2383 점심 식사시간
  9. 2022.05.14 2382 미생물 격리
  10. 2022.05.14 2117 홈 방범 서비스
PS/BOJ2022. 5. 20. 23:13

 

 

 

#전략 1

기존 풀이는 visited 및 check 그리고 dis배열을 활용하여 직관적으로 풀이하려했다.

결과는 13번째 TC에서 fail인데 이유를 구체적으로 알 수가 없고, 시간관계상 다른 풀이를 검색해보았다.

로직상으로 문제가 없다고 생각 되지만, 사용하는 배열이 많아 어딘가 예외적인 케이스가 분명 발생할 것으로 추측된다.

(한마디로 비효율적인 접근법이었다는 의미)

import java.util.Arrays;
import java.util.LinkedList;
import java.util.Queue;
import java.util.StringTokenizer;
import java.io.BufferedReader;
import java.io.File;
import java.io.InputStreamReader;
import java.io.PrintStream;

class Solution {

	static int N, ans;
	static boolean DBG = false;

	
	static class Atom {
		int x, y, d, k, id;
		int impactTime;// 동시간에 충돌했는지를 확인하기 위한 변수

		Atom(int id, int x, int y, int d, int k) {
			this.id = id;
			this.x = x;
			this.y = y;
			this.d = d;
			this.k = k;
			this.impactTime = 0;
		}

		public void progress() {
			x += dx[d];
			y += dy[d];
		}

		public int getDistance(Atom o) {
			return Math.abs(x - o.x) + Math.abs(y - o.y);
		}

		public boolean isImpactable(Atom o) {

			int dis = getDistance(o);
			// 거리가 0인 경우 충돌 가능
			if (dis == 0)
				return true;
			// 거리가 1이 아닌 경우 충돌 불가
			if (dis != 1)
				return false;
			// x축에 나란한 경우
			if (y == o.y) {
				if (x < o.x) {
					if (d == LEFT && o.d == RIGHT)
						return true;
					if (d == RIGHT && o.d == LEFT)
						return false;
				}
				if (x > o.x) {
					if (d == RIGHT && o.d == LEFT)
						return true;
					if (d == LEFT && o.d == RIGHT)
						return false;
				}
			}
			// y축에 나란한 경우
			if (x == o.x) {
				if (y < o.y) {
					if (d == UP && o.d == DOWN)
						return true;
					if (d == DOWN && o.d == UP)
						return false;
				}
				if (y > o.y) {
					if (d == DOWN && o.d == UP)
						return true;
					if (d == UP && o.d == DOWN)
						return false;
				}
			}

			if (DBG)
				System.out.printf("unexpected false id [%d][%d]return dis : %d x,y[%d %d] o.x,o.y[%d %d]\n", id, o.id,
						dis, x, y, o.x, o.y);
			return false;
		}

	}

	static int[] dx = { 0, 0, -1, 1 };
	static int[] dy = { 1, -1, 0, 0 };
	static final int UP = 0;
	static final int DOWN = 1;
	static final int LEFT = 2;
	static final int RIGHT = 3;
	static boolean[][] visited;
	static boolean[] check;
	// static boolean[] visited;
	static int[][] dis; // 거리가 멀어지고 있는지 확인하기 위한 dis배열
	static Atom[] arr;

	static Queue<Atom> queue;

	public static void main(String args[]) throws Exception {

		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		StringTokenizer st;
		if (DBG) {
			File file = new File(
					"C:\\Users\\Lee\\eclipse-workspace\\TestApplication\\src\\com\\test\\testapplication\\output.txt");
			PrintStream ps = new PrintStream(file);
			System.setOut(ps);
		}
		int T;
		T = Integer.parseInt(br.readLine());
		for (int test_case = 1; test_case <= T; test_case++) {
			N = Integer.parseInt(br.readLine());
			arr = new Atom[N];
			visited = new boolean[N][N];
			for ( int i  = 0 ; i < N ; i++) {
				for ( int j = 0 ; j < N ; j++) {
					if (i==j)
						visited[i][j]=true;
				}
			}
			
			check= new boolean[N];
			// visited = new boolean[N];
			dis = new int[N][N];

			queue = new LinkedList<>();
			for (int i = 0; i < N; i++) {
				st = new StringTokenizer(br.readLine());
				int id = i;
				int x = Integer.parseInt(st.nextToken());
				int y = Integer.parseInt(st.nextToken());
				int d = Integer.parseInt(st.nextToken());
				int k = Integer.parseInt(st.nextToken());

				queue.add(new Atom(id, x, y, d, k));

				Arrays.fill(dis[i], Integer.MAX_VALUE);
			}

			ans = 0;
			simultation();
			System.out.println("#" + test_case + " " + ans);
		}
	}

	private static void simultation() {
		int time = 1;
		Atom now;
		while (!queue.isEmpty()) {

			int size = queue.size();

			// 점 하나는 해결할 수 없다.
			if (size == 1)
				return;
			if (DBG)
				System.out.println("@@@@@@@time : " + time + " qsize : " + size);
			for (int q = 0; q < size; ++q) {
				now = queue.poll();
				int nowId = now.id;
				// 충돌여부 확인
				for (Atom atom : queue) {
					// 비교대상의 id
					int nextId = atom.id;
					// 이미 충돌했고, 충돌시간이 현재 시각과 다르면 건너 뜀.
					if (visited[nowId][nextId] && atom.impactTime != 0)
						continue;

					int currentDis = now.getDistance(atom);
					if (DBG)
						System.out.printf("DBG[%d][%d][dis : %d][%d and %d] ans : %d\n", nowId, nextId,
								dis[nowId][nextId], nowId, nextId, ans);
					// 현재거리가 이전 거리보다 멀어졌으면, 영원히 만나지 않으므로 방문처리.
					if (dis[nowId][nextId] <= currentDis) {
						if (DBG)
							System.out.printf(
									"CRITICAL : nowId :%d and nextId %d never meet  dis : %d currentDis : %d\n", nowId,
									nextId, dis[nowId][nextId], currentDis);
						visited[nowId][nextId] = true;
						visited[nextId][nowId] = true;
						continue;
					}
					dis[nowId][nextId] = currentDis;
					if (now.isImpactable(atom)) {
						// 상대를 방문처리. -> 디버깅 후 위의 로직과 합해도 됨.
						visited[nowId][nextId] = true;
						visited[nextId][nowId] = true;
						atom.impactTime = time;
						now.impactTime = time;
						if(!check[nextId] ) {
							ans += atom.k;
							check[nextId]=true;
						}
						if (!check[nowId]) {
							ans += now.k;
							check[nowId]=true;
						}
						if (DBG)
							System.out.printf("[dis : %d][%d and %d]					crashed ans : %d\n", dis[nowId][nextId], nowId,
									nextId, ans);
					}

				}

				boolean isAllVisited = true;
				for ( int i = 0 ; i < N ; i++) {
					for ( int j = 0 ; j < N; j++) {
						if( i!=j && !visited[i][j]) {
							isAllVisited = false;
							break;
						}
					}
				}
				/*
				for (boolean[] ar : visited) {
					for (boolean b : ar) {
						System.out.printf("%b ",b);
					}
					System.out.println();
				}
				*/

				if (isAllVisited) {
					if (DBG)
						System.out.println("ALL atoms visited or never met finish program");
					return;
				}

				// 충돌하지 않은 경우 다시 enqueue
				if (!check[now.id])
					queue.offer(now);
			}
			// 모든 검사가 끝난 이후 원자들을 업데이트 해준다.
			for (Atom atom : queue) {
				// 충돌 시간이 0이 아닌 경우 충돌한것으로 간주
				if (atom.impactTime != 0)
					continue;
				if (DBG)
					System.out.printf("move id:%d [x:%5d y:%5d][d : %d]\n", atom.id, atom.x, atom.y, atom.d);
				atom.progress();
			}

			time++;
		}

	}

}

 

 

#전략 2.(남의 답)

 

역시나 남의 코드를 분석하면 배울점이 많다.

 

1. 입력

- 최초 입력값을 x, y가 아닌 y, x 로 받아 배열의 x,y를 실제 수학의 좌표와 같이 사용할 수 있도록 구성한다.

*(배열의 최대크기 - x 를 하므로써 배열의 인덱스 반대방향으로 진행하게끔 만듦)

*(x,y 입력 순서가 달라지므로, 기존 배열탐색으로 y/x축 대칭이 일어남)

 

ex) 2, 3

y=         (y + 1000) << 1  

=> 2004

x= 4000 - ((x + 1000) <<1) 

=> 4000 - 2006

 

배열인덱스의 (2000,2000)를 원점으로 x는 일반 좌표계의 y축, y는 x축을 의미.

map[1994][2004]는 일반좌표계의 원점(0,0)을 기준으로 (4,6)과 동일하다

 

위와 같이 shifting으로 2배증가 시킨 이유를 생각해보면 너무 멋지다.

 

전략1에서 생각했던 대로면, dis값이 0, 1인 경우와 방향을 모두 고려해야 충돌여부를 판단할 수 있으나,

scale이 2배가 되면, 아래 코드와 같이 map의 값을 순차적으로 이동시켜도 중복이 발생하지 않게 된다.

ex)

아래의 예에서 현재 값을 이동하고 다음 값을 이동하게 되면, 어쩔 수 없이 기존값에 영향을 받게 된다.

(o)=><=(o)

 

하지만 scale이 2배가 되면?

(o)=>( )<=(o)

좌,우 어떤 값이든 먼저 옮긴 후, 나머지를 차례로 옮겨도 결과에는 차이가 없게된다.

 

이게 상,하,좌,우 모두에 통하기 때문에 아래와 같이 코드가 간결해진다.

 

 

경계에 도달하는 경우는 겹치는 원자가 없음을 나타내며 map의 값이 현재(now) 값과 다른 것은 충돌이 일어났음을 의미한다.

 

 

import java.util.Arrays;
import java.util.LinkedList;
import java.util.Queue;
import java.util.StringTokenizer;
import java.io.BufferedReader;
import java.io.File;
import java.io.InputStreamReader;
import java.io.PrintStream;

class Solution {

	static int N, ans;
	static boolean DBG = false;

	
	static class Atom {
		int x, y, d, k;

		Atom( int x, int y, int d, int k) {
			this.x = x;
			this.y = y;
			this.d = d;
			this.k = k;
		}

	}
	static int[] dx = { -1, 1, 0, 0 };//xy대칭 및 부호가 반대
	static int[] dy = {  0, 0 , -1,1 };//xy대칭
	static final int UP = 0;
	static final int DOWN = 1;
	static final int LEFT = 2;
	static final int RIGHT = 3;
	static int[][] map;
	
	static Queue<Atom> queue;

	public static void main(String args[]) throws Exception {

		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		StringTokenizer st;
		
		int T;
		T = Integer.parseInt(br.readLine());
		for (int test_case = 1; test_case <= T; test_case++) {
			N = Integer.parseInt(br.readLine());

			queue = new LinkedList<>();
			
			map = new int[4002][4002];
			
			for (int i = 0; i < N; i++) {
				st = new StringTokenizer(br.readLine());
				//x의 부호를 변경하고 x,y를 대칭으로 만들어 실제 좌표계와 같이 사용할 수 있게 변형됨.
				int y = Integer.parseInt(st.nextToken());
				y =  ((y+1000)<<1);				
				int x = Integer.parseInt(st.nextToken());
			    x = 4000 - ( (x+ 1000) <<1));
				int d = Integer.parseInt(st.nextToken());
				int k = Integer.parseInt(st.nextToken());
				map[x][y] = k;
				queue.add(new Atom(x,y,d,k));

			}
			ans = 0;
			bfs();

			System.out.println("#" + test_case + " " + ans);
		}
	}

	private static void bfs() {
			while(!queue.isEmpty()) {
				Atom n = queue.poll();
				
				//현재 자리가 내가 가진 값과 다른때
				if ( map[n.x][n.y] != n.k) {
					
					ans += map[n.x][n.y];
					map[n.x][n.y] =0;
					continue;
				} 
				
				int nx = n.x + dx[n.d];
				int ny = n.y + dy[n.d];
				
				if( nx>=0 && nx <=4000 && ny >=0 && ny <= 4000) {
					
					if(map[nx][ny] == 0) {
						map[nx][ny] = n.k;
						queue.add(new Atom(nx,ny,n.d,n.k));
					}
					else {
						map[nx][ny] += n.k;
					}
					
				}
				//원래 있던 곳을 비움
				map[n.x][n.y] = 0;
			}
	}
}

 

 

 

 

 

'PS > BOJ' 카테고리의 다른 글

5650 핀볼게임  (0) 2022.05.20
5656 벽돌깨기  (0) 2022.05.17
5658 보물상자 비밀번호  (0) 2022.05.16
5644 무선 충전  (0) 2022.05.16
4014 활주로 탐색  (0) 2022.05.15
Posted by easy16
PS/BOJ2022. 5. 20. 01:46

 

평이한 수준의 문제였으나 웜홀에 대한 처리가 미숙했다. (44번 case 에서 fail)

아래의 웜홀 검사에서 break를 사용하지 않아, 좌표가 업데이트된 이후, 또다시 원래의 웜홀로 돌아오게 되었다..

무언가를 탐색하고 업데이트를 하면 반드시 루프를 종료할 것.

 

이런 부분은 정말 찾기가 힘든것 같다. 평소에 주의하여 코딩하는 수 밖에 없다.

                for (P p : wh) {
                    if (p.id == brick && (p.x != x || p.y != y)) {// 웜홀 이동.                    	
                        update(p.x, p.y);
                        break;
                    }
                }

 

 

import java.util.ArrayList;
import java.util.StringTokenizer;
import java.io.BufferedReader;
import java.io.InputStreamReader;

 
class Solution {
 
    static int N, ans;
    static boolean DBG = false;
    static int[][] map;
    static int[] dx = { -1, 1, 0, 0 };
    static int[] dy = { 0, 0, -1, 1 };
    private static int max;
 
    static final int UP = 0;
    static final int DOWN = 1;
    static final int LEFT = 2;
    static final int RIGHT = 3;
 
    static class Ball {
        int x, y;
        int d;// direction
        int cnt;
 
        Ball(int x, int y, int d) {
            this.x = x;
            this.y = y;
            this.d = d;
            this.cnt = 0;
        }
 
        void process(int brick) {
            switch (brick) {
            case 1:
                if (d == UP)
                    d = DOWN;
                else if (d == DOWN)
                    d = RIGHT;
                else if (d == LEFT)
                    d = UP;
                else if (d == RIGHT)
                    d = LEFT;
                count();
                break;
            case 2:
                if (d == UP)
                    d = RIGHT;
                else if (d == DOWN)
                    d = UP;
                else if (d == LEFT)
                    d = DOWN;
                else if (d == RIGHT)
                    d = LEFT;
                count();
                break;
            case 3:
                if (d == UP)
                    d = LEFT;
                else if (d == DOWN)
                    d = UP;
                else if (d == LEFT)
                    d = RIGHT;
                else if (d == RIGHT)
                    d = DOWN;
                count();
                break;
            case 4:
                if (d == UP)
                    d = DOWN;
                else if (d == DOWN)
                    d = LEFT;
                else if (d == LEFT)
                    d = RIGHT;
                else if (d == RIGHT)
                    d = UP;
                count();
                break;
            case 5:
                if (d == UP)
                    d = DOWN;
                else if (d == DOWN)
                    d = UP;
                else if (d == LEFT)
                    d = RIGHT;
                else if (d == RIGHT)
                    d = LEFT;
                count();
                break;
            case 6:
            case 7:
            case 8:
            case 9:
            case 10:
                for (P p : wh) {
                    if (p.id == brick && (p.x != x || p.y != y)) {// 웜홀 이동.                    	
                        update(p.x, p.y);
                        break;
                    }
                }
                break;
            }
        }
 
        public void count() {
            cnt++;
        }
 
        public void update(int x, int y) {
            this.x = x;
            this.y = y;
        }
    }
 
    static ArrayList<P> bh, wh;
 
    static class P {
        public int x, y;
        public int id;
 
        P(int x, int y) {
            this.x = x;
            this.y = y;
            this.id = -1;
        }
 
        P(int x, int y, int id) {
            this.x = x;
            this.y = y;
            this.id = id;
        }
    }
 
    public static void main(String args[]) throws Exception {
 
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st;
        int T;
        T = Integer.parseInt(br.readLine());
        for (int test_case = 1; test_case <= T; test_case++) {
            N = Integer.parseInt(br.readLine());
            max = 0;
            map = new int[N][N];
            wh = new ArrayList<>();
            bh = new ArrayList<>();
            for (int i = 0; i < N; i++) {
                st = new StringTokenizer(br.readLine());
                for (int j = 0; j < N; j++) {
                    map[i][j] = Integer.parseInt(st.nextToken());
                    if (map[i][j] >= 6 && map[i][j] <= 10) {
                        wh.add(new P(i, j, map[i][j]));
                    }
                    if (map[i][j] == -1) {
                        bh.add(new P(i, j));
                    }
 
                }
            }
 
            for (int i = 0; i < N; i++) {
                for (int j = 0; j < N; j++) {
                    if (map[i][j] == 0) {
                        int value = simulation(i, j);
                        max = Math.max(value, max);
                    }
                }
            }
            System.out.println("#" + test_case + " " + max);
        }
    }
 
    private static int simulation(int r, int c) {
        int max = 0;
 
        Ball ball;
        // 한지점에서 상하좌우의 이동경우 중, 최대값을 구하여 리턴
        for (int i = 0; i < 4; i++) {
            int nr = r;
            int nc = c;
            ball = new Ball(nr, nc, i);
        
            while (true) {	
                nr = ball.x + dx[ball.d];
                nc = ball.y + dy[ball.d];

                // 경계선인 경우,
                if (nr < 0 || nr >= N || nc < 0 || nc >= N) {
                    // 방향을 변경
                    ball.d = reverseDirection(ball.d);
                    ball.update(nr, nc);
                    ball.count();
                    continue;
                }
 
                // 블랙홀 또는 시작위치인 경우,
                if (map[nr][nc] == -1 || (nr == r && nc == c)) {
                    // 종료
                    max = Math.max(max, ball.cnt);
                    break;
                }
 
                // 빈공간인 경우.
                if (map[nr][nc] == 0) {
                    // 전진
                    ball.update(nr, nc);
                } else {
                    // 이동 후, 기타 블럭 처리
                    ball.update(nr, nc);
                    ball.process(map[nr][nc]);
                }
            }
 
        }
        return max;
    }
 
    static int reverseDirection(int d) {
        if (d == UP)
            return DOWN;
        if (d == DOWN)
            return UP;
        if (d == RIGHT)
            return LEFT;
        return RIGHT;
    }
}

'PS > BOJ' 카테고리의 다른 글

5648 원자소멸 시뮬레이션  (0) 2022.05.20
5656 벽돌깨기  (0) 2022.05.17
5658 보물상자 비밀번호  (0) 2022.05.16
5644 무선 충전  (0) 2022.05.16
4014 활주로 탐색  (0) 2022.05.15
Posted by easy16
PS/BOJ2022. 5. 17. 23:14

 

전략

1. Colum 의 인덱스를 중복이 되도록 N개의 순열을 만들어준다. 

2. 만들어진 순열을 Simulation하여 남은 블록을 센다

3. 그중 최소값을 찾는다.

 

 

인덱스 삽질로 시간을 허비했다.

제출 후, 47번째 TC에서 fail 했으나 유사한 사례를 검색을 통해 찾게 되었다. (참조 사이트)

map을 만들 때, H를 하나 더 증가시켜서 문제 조건의 하나인 맨 윗칸을 비우는 것을 충족시켰다.

 

그런데 왜 맨위가 비었다는 이유로 Pass가 되는지는 아직도 모르겠다.

높이가 H인 경우의 반례를 생각해보려 했으나 코드 동작상 아무런 차이가 없다.

 

import java.util.Arrays;
import java.util.StringTokenizer;
import java.io.BufferedReader;
import java.io.File;
import java.io.InputStreamReader;
import java.io.PrintStream;

class Solution {

	static int N, H, W;
	static boolean DBG = false;
	static int[][] map, dummy;
	private static int ans;
	static int totalBricks;
	static int dummyTotalBricks;

	public static void main(String args[]) throws Exception {

		
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		/*
		File file = new File(
				"C:\\Users\\Lee\\eclipse-workspace\\TestApplication\\src\\com\\test\\testapplication\\output.txt");
		PrintStream ps = new PrintStream(file);
		System.setOut(ps);
		 */

		int T;
		T = Integer.parseInt(br.readLine());

		StringTokenizer st = null;

		for (int test_case = 1; test_case <= T; test_case++) {
			st = new StringTokenizer(br.readLine());
			N = Integer.parseInt(st.nextToken());
			W = Integer.parseInt(st.nextToken());
			H = Integer.parseInt(st.nextToken());
			totalBricks=0;
			ans = Integer.MAX_VALUE;
			map = new int[H+1][W];
			
			for (int i = 1; i <= H; i++) {
				st = new StringTokenizer(br.readLine());
				for (int j = 0; j < W; j++) {
					map[i][j] = Integer.parseInt(st.nextToken());
					if (map[i][j] != 0)
						++totalBricks;
				}
			}
			go(0, new int[N]);
			// UnitTest();
			System.out.println("#" + test_case + " " + ans);
		}
	}

	// 중복 순열 : [0,W]사이의 인덱스를 선택하는 경우의 수,
	private static void go(int level,  int[] perm) {
		if (level == N) {
			if (DBG) {
				StringBuilder sb = new StringBuilder();
				for (int v : perm) {
					sb.append(v).append(' ');
				}
				System.out.println(sb);
			}

			dummy = new int[H+1][W];

			for (int i = 0; i <= H; i++) {
				dummy[i] = Arrays.copyOf(map[i], W);
			}

			int rest = simulation(perm);
			ans = Math.min(rest, ans);

		} else {
			for (int i = 0; i < W; i++) {
				perm[level] = i;
				go(level + 1, perm);
			}

		}
	}

	private static void UnitTest() {
		dummy = new int[H+1][W];

		for (int i = 0; i <= H; i++) {
			dummy[i] = Arrays.copyOf(map[i], W);
		}

		int[] perm = new int[3];
		perm[0] = 2;
		perm[1] = 2;
		perm[2] = 6;
		int rest = simulation(perm);
		sort();
		ans = Math.min(rest, ans);

	}

	private static int simulation(int[] perm) {
		dummyTotalBricks = totalBricks;
		for (int i = 0; i < perm.length/* N */ ; i++) {
			int c = perm[i];
			if (DBG)
				System.out.printf("perm[%d] c : %d\n", i, perm[i]);
			for (int r = 0; r <= H; r++) {
				if (dummy[r][c] == 0)
					continue;
				// 스플레시
				int width = dummy[r][c];
				explode(r, c, width);

				if (DBG) {
					System.out.printf("r : %d c: %d width : %d dummyTotalBricks : %d\n", r, c, width, dummyTotalBricks);
					for (int[] ar : dummy) {
						for (int v : ar) {
							System.out.print(v + " ");
						}
						System.out.println();
					}
				}

				sort();
				if (DBG) {
					System.out.println("after sort");
					for (int[] ar : dummy) {
						for (int v : ar) {
							System.out.print(v + " ");
						}
						System.out.println();
					}
				}
				break;
			}
		}
		return dummyTotalBricks;
	}

	private static void sort() {
		// 블록들을 정리한다.
		for (int i = 0; i < W; i++) {
			for (int j = H; j > 1; j--) {
				if (dummy[j][i] == 0) {
					for (int k = j - 1; 0 <= k; k--) {
						if (dummy[k][i] != 0) {
							dummy[j][i] = dummy[k][i];
							dummy[k][i] = 0;
							break;
						}
					}
				}
			}
		}
	}

	static int[] dx = { 0, 0, -1, 1 };
	static int[] dy = { 1, -1, 0, 0 };

	private static void explode(int r, int c, int width) {

		// 현재 터진 자리를 0으로 지운다.
		dummy[r][c] = 0;
		if (DBG)
			System.out.printf("set 0 %d %d %d\n", r, c, dummy[r][c]);
		// 터질 때마다 남은 블록수를 count한다.
		dummyTotalBricks--;

		for (int d = 0; d < 4; d++) {
			for (int w = 1; w < width; w++) {
				// 폭발의 범위내에 터질 블록이 있으면 폭파 시킨다.
				int nr = r + w * dx[d];
				int nc = c + w * dy[d];
				if (nr >= 0 && nr <= H && nc >= 0 && nc < W && dummy[nr][nc] != 0) {
					int nWidth = dummy[nr][nc];
					explode(nr, nc, nWidth);
				}
			}
		}
	}

}

 

 

참조 : https://jongnan.tistory.com/entry/SW-Expert-5656-%EB%B2%BD%EB%8F%8C-%EA%B9%A8%EA%B8%B0

'PS > BOJ' 카테고리의 다른 글

5648 원자소멸 시뮬레이션  (0) 2022.05.20
5650 핀볼게임  (0) 2022.05.20
5658 보물상자 비밀번호  (0) 2022.05.16
5644 무선 충전  (0) 2022.05.16
4014 활주로 탐색  (0) 2022.05.15
Posted by easy16
PS/BOJ2022. 5. 16. 22:45

모의 테스트 문제중 제일 쉬운 문제 같다.

 

rotation => right or left shift -> substring(1,len) + s.charAt(0);

Hex String -> Integer.parseInt( K th value, 16 );

 

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedList;
import java.util.PriorityQueue;
import java.util.Queue;
import java.util.StringTokenizer;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStreamReader;
import java.io.PrintStream;

class Solution {

	static int N, K, W;

	private static boolean DBG = false;
	static String s;

	public static void main(String args[]) throws Exception {

		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

		int T;
		T = Integer.parseInt(br.readLine());

		StringTokenizer st = null;

		for (int test_case = 1; test_case <= T; test_case++) {
			st = new StringTokenizer(br.readLine());
			N = Integer.parseInt(st.nextToken());
			K = Integer.parseInt(st.nextToken());
			s = br.readLine();

			W = N / 4;
			ArrayList<String> answer = new ArrayList<>();

			for (int t = 0; t < W; t++) {
				for (int i = 0; i < N; i += W) {
					String sub = s.substring(i, i + W);
					if (!answer.contains(sub))
						answer.add(sub);
				}
				s = rightShift();
				
			}

			Collections.sort(answer, Collections.reverseOrder());
		
			if(DBG) {
				for (String str : answer) {
					System.out.print(str + " ");
				}
				System.out.println();
			}
			
			
			System.out.println("#" + test_case + " "+Integer.parseInt(answer.get(K-1),16));
		}
	}

	private static String rightShift() {
		StringBuilder sb = new StringBuilder();
		return sb.append(s.charAt(s.length()-1)).append(s.substring(0, s.length()-1)).toString();
	}

}

'PS > BOJ' 카테고리의 다른 글

5650 핀볼게임  (0) 2022.05.20
5656 벽돌깨기  (0) 2022.05.17
5644 무선 충전  (0) 2022.05.16
4014 활주로 탐색  (0) 2022.05.15
4013 특이한 자석  (0) 2022.05.15
Posted by easy16
PS/BOJ2022. 5. 16. 01:28

 

BC에 대한 중복을 어떻게 처리할 것인지가 가장 어려웠던 부분.

처음 작성한 것이 오답인데 해결이 잘 안됐으나 아래의 참조사이트의 비교 구문을 사용 후 Pass 되었다.

 

ArrayList 2개에서 maxP를 구하는 부분이 핵심이다.

 

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedList;
import java.util.PriorityQueue;
import java.util.Queue;
import java.util.StringTokenizer;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStreamReader;
import java.io.PrintStream;

class BC {
	int x, y, c, p;

	BC(int x, int y, int c, int p) {
		this.x = x;
		this.y = y;
		this.c = c;
		this.p = p;
	}

	public boolean isCovered(P p) {
		return (Math.abs(p.x - x) + Math.abs(p.y - y) <= c);
	}

}

class P {
	int x, y;

	P(int x, int y) {
		this.x = x;
		this.y = y;
	}

}

class Solution {

	static int M, A;

	private static boolean DBG = false;
	private static int ans;

	static int[][] player;
	static int[] dx = { 0, 0, 1, 0, -1 };
	static int[] dy = { 0, -1, 0, 1, 0 };
	static BC[] bcList;
	static P[] pList;
	static ArrayList<Integer> scores;
	static Queue<P>[] Q;

	public static void main(String args[]) throws Exception {

		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

		int T;
		T = Integer.parseInt(br.readLine());

		StringTokenizer st = null;

		for (int test_case = 1; test_case <= T; test_case++) {
			st = new StringTokenizer(br.readLine());
			M = Integer.parseInt(st.nextToken());
			A = Integer.parseInt(st.nextToken());

			// 시작점을 테스트하기 위해 0번 인덱스를 비워둠
			player = new int[2][M + 1];
			scores = new ArrayList<>();
			for (int i = 0; i < 2; i++) {
				st = new StringTokenizer(br.readLine());
				for (int j = 1; j <= M; j++) {
					player[i][j] = Integer.parseInt(st.nextToken());
				}
			}

			pList = new P[2];
			pList[0] = new P(1, 1);
			pList[1] = new P(10, 10);

			bcList = new BC[A];

			for (int i = 0; i < A; i++) {
				st = new StringTokenizer(br.readLine());
				int x = Integer.parseInt(st.nextToken());
				int y = Integer.parseInt(st.nextToken());
				int c = Integer.parseInt(st.nextToken());
				int p = Integer.parseInt(st.nextToken());
				bcList[i] = new BC(x, y, c, p);
			}
			// level, time, sum
			simulation();
			ans = 0;
			for (int v : scores) {
				ans += v;
			}

			System.out.println("#" + test_case + " " + ans);
		}
	}

	private static void simulation() {
		int time = 0;

		while (true) {
			ArrayList<BC>[] power = new ArrayList[2];
			power[0] = new ArrayList<BC>();
			power[1] = new ArrayList<BC>();

			if (time == M + 1) {
				break;
			}

			for (int i = 0; i < 2; i++) {
				P p = pList[i];

				int nx = p.x + dx[player[i][time]];
				int ny = p.y + dy[player[i][time]];

				p.x = nx;
				p.y = ny;

				for (int j = 0; j < A; j++) {
					BC bc = bcList[j];
					if (bc.isCovered(p)) {
						power[i].add(bc);
					}
				}

			}

			for (int i = 0; i < 2; i++) {
				Collections.sort(power[i], (a, b) -> {
					return b.p - a.p;
				});
			}

			int maxP = 0;
			if (!power[0].isEmpty() || !power[1].isEmpty()) {
				//둘다 요소가 있는 경우
				if (!power[0].isEmpty() && !power[1].isEmpty()) {
					if (power[0].get(0) == power[1].get(0)) {
						if (power[0].size() >= 2)
							maxP = Math.max(power[0].get(0).p + power[0].get(1).p, maxP);
						if (power[1].size() >= 2)
							maxP = Math.max(power[1].get(0).p + power[1].get(1).p, maxP);
                        //이부분에서 사이즈가 1인 경우는 고려되지 않았음.
                        //아래의 코드를 추가 후, else를 추가하여 가독성을 높일 수 있음.
                        //중복된 BC가 있기 떄문에 power1/0 둘중 아무거나 택한다.
                        maxP = Math.max(power[1].get(0).p, maxP);
					} else {
						maxP = Math.max(power[0].get(0).p + power[1].get(0).p, maxP);
					}
                } else {//둘 중 하나만 요소가 있는 경우
                    if (!power[0].isEmpty())
                        maxP = Math.max(power[0].get(0).p, maxP);
                    if (!power[1].isEmpty())
                        maxP = Math.max(power[1].get(0).p, maxP);
                }

			}
			scores.add(maxP);

			time++;
		}
	}

}

 

 

참조 사이트 : https://imksh.com/54

 

 

 

 

'PS > BOJ' 카테고리의 다른 글

5656 벽돌깨기  (0) 2022.05.17
5658 보물상자 비밀번호  (0) 2022.05.16
4014 활주로 탐색  (0) 2022.05.15
4013 특이한 자석  (0) 2022.05.15
2383 점심 식사시간  (0) 2022.05.15
Posted by easy16
PS/BOJ2022. 5. 15. 22:34

 

 

BF로 완전탐색해도 문제가 없었다.

두번정도 수정 후, 제출시 40번에서 fail이 발생했다. 

아래의 반례에서 fail이 되었는데, 2 1 1 1 2  를 처리할 때 활주로 건설 후, dupCnt를 1로 초기화 한것이 문제였다.

이를 0으로 변경 후, Pass 됨.

다른 풀이를 찾아보니 검사를 dfs로 하는 방법도 있다.

 

1
6 2
2 1 2 1 2 3
2 1 2 1 2 1
2 1 2 1 2 3
2 1 2 1 2 3
3 5 6 5 5 5
2 1 1 1 2 2

 

 

 

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedList;
import java.util.PriorityQueue;
import java.util.Queue;
import java.util.StringTokenizer;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStreamReader;
import java.io.PrintStream;

class Solution {

	static int N, X;
	static int[][] map;

	private static boolean DBG = false;
	private static int ans;

	public static void main(String args[]) throws Exception {

		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

		int T;
		T = Integer.parseInt(br.readLine());

		StringTokenizer st = null;

		for (int test_case = 1; test_case <= T; test_case++) {
			st = new StringTokenizer(br.readLine());
			N = Integer.parseInt(st.nextToken());
			X = Integer.parseInt(st.nextToken());

			map = new int[N][N];

			for (int i = 0; i < N; i++) {
				st = new StringTokenizer(br.readLine());
				for (int j = 0; j < N; j++) {
					map[i][j] = Integer.parseInt(st.nextToken());
				}
			}
			ans = 0;

			for (int i = 0; i < N; i++) {
				int dupCnt = 1;
				boolean result = true;
				boolean isDownHill = false;

				for (int j = 1; j < N; j++) {
					if (map[i][j - 1] == map[i][j]) {
						++dupCnt;
						// 내리막에서 활주로를 건설하고 카운트 초기화
						if (isDownHill && dupCnt == X) {
							isDownHill = false;
							dupCnt = 0;
							//j++;
						}

					} else if (map[i][j - 1] - map[i][j] == -1 ) {
						// 오르막을 만난 경우, 카운트가 X보다 작을 경우, 활주로 건설 불가
						if (dupCnt >= X) {
							dupCnt = 1;
							
						} else {
							result = false;
							break;
						}
					} else if (map[i][j - 1] - map[i][j] == 1) {
						// 내리막을 발견하면 카운트를 초기화하고 내리막을 표시
						if (!isDownHill) {
							isDownHill = true;
							dupCnt = 1;						
						} else {
							// 내리막에서 활주로 건설 없이 다시 내리막을 만난 경우
							result = false;
							break;
						}
					} else {
						result = false;
						break;
					}
				}

				if (!isDownHill && result)
					ans++;

			}

			for (int i = 0; i < N; i++) {
				int dupCnt = 1;
				boolean result = true;
				boolean isDownHill = false;

				for (int j = 1; j < N; j++) {
					if (map[j - 1][i] == map[j][i]) {
						++dupCnt;
						// 내리막에서 활주로를 건설하고 카운트 초기화
						if (isDownHill && dupCnt == X) {
							isDownHill = false;
							dupCnt = 0;
							//j++;
						}

					} else if (map[j - 1][i] - map[j][i] == -1) {
						// 오르막을 만난 경우, 카운트가 X보다 작을 경우, 활주로 건설 불가
						if (dupCnt >= X) {
							dupCnt = 1;
						} else {
							result = false;
							break;
						}
					} else if (map[j - 1][i] - map[j][i] == 1) {
						// 내리막을 발견하면 카운트를 초기화하고 내리막을 표시
						if (!isDownHill) {
							isDownHill = true;
							dupCnt = 1;
						} else {
							// 내리막에서 활주로 건설 없이 다시 내리막을 만난 경우
							result = false;
							break;
						}
					} else {
						result = false;
						break;
					}
				}

				if (!isDownHill && result)
					ans++;

			}

			System.out.println("#" + test_case + " " + ans);
		}
	}

}

'PS > BOJ' 카테고리의 다른 글

5658 보물상자 비밀번호  (0) 2022.05.16
5644 무선 충전  (0) 2022.05.16
4013 특이한 자석  (0) 2022.05.15
2383 점심 식사시간  (0) 2022.05.15
2382 미생물 격리  (0) 2022.05.14
Posted by easy16
PS/BOJ2022. 5. 15. 20:58

 

기어를 돌리는 행위를 Queue를 통해 해결하고, 기어의 상태변화를 dfs로 해결했다.

for문으로 사용하는 아이디어가 번거롭다고 생각하여 dfs로 해결했으나, 다른 풀이를 찾아보니, 좌우로 for문을 한번씩 순회하여 해결한 방법이 있었다.

 

for문을 사용하는 경우를 떠올렸을 때, 하나의 for문으로만 해결하려고 했던 것이 문제해결을 복잡하게 만든 원인이었다.

순차 탐색의 경우, 이번 경우를 기억해 두면 쓸모가 있을 것 같다.

 

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedList;
import java.util.PriorityQueue;
import java.util.Queue;
import java.util.StringTokenizer;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStreamReader;
import java.io.PrintStream;

class Solution {

	static int N;
	static int[][] gear;
	static int[][] input;
	static int[] check;

	private static int ans;
	private static boolean DBG = false;

	public static void main(String args[]) throws Exception {

		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

		int T;
		T = Integer.parseInt(br.readLine());

		StringTokenizer st = null;

		for (int test_case = 1; test_case <= T; test_case++) {
			st = new StringTokenizer(br.readLine());
			N = Integer.parseInt(st.nextToken());

			gear = new int[4][8];

			for (int i = 0; i < 4; i++) {
				st = new StringTokenizer(br.readLine());
				for (int j = 0; j < 8; j++) {
					gear[i][j] = Integer.parseInt(st.nextToken());
				}
			}

			input = new int[N][2];
			for (int i = 0; i < N; i++) {
				st = new StringTokenizer(br.readLine());
				input[i][0] = Integer.parseInt(st.nextToken());
				input[i][1] = Integer.parseInt(st.nextToken());
			}
			ans = 0;
			bfs();

			System.out.println("#" + test_case + " " + ans);
		}
	}

	private static void bfs() {
		Queue<int[]> Q = new LinkedList<>();

		for (int[] in : input) {
			Q.offer(in);
		}

		int level = 0;
		while (!Q.isEmpty()) {
			int size = Q.size();
			for (int q = 0; q < size; q++) {
				int[] now = Q.poll();
				int k = now[0] - 1;
				int d = now[1];
				check = new int[4];
				go(0, k, d);
				for (int i = 0; i < check.length; i++) {
					if (DBG)
						System.out.printf("%d ", check[i]);
					shift(gear[i], check[i]);
				}
				if (DBG)
					System.out.println();

				if (DBG) {
					for (int[] ar : gear) {
						for (int v : ar) {
							System.out.printf("%d ", v);
						}
						System.out.println();
					}
				}

			}
			level++;
		}

		int sum = 0;
		int idx = 0;
		for (int[] ar : gear)
			sum += ar[0] * Math.pow(2, idx++);

		ans = sum;
	}

	private static void go(int level, int idx, int d) {

		if (check[idx] != 0)
			return;
		if (DBG)
			System.out.printf("[go] idx : %d d : %d\n", idx, d);
		check[idx] = d;

		if (idx + 1 < 4 && gear[idx][2] != gear[idx + 1][6])
			go(level + 1, idx + 1, d * -1);

		if (idx - 1 >= 0 && gear[idx][6] != gear[idx - 1][2])
			go(level + 1, idx - 1, d * -1);

	}

	static void shift(int[] arr, int d) {
		// 시계
		if (d == 1) {
			int tmp = arr[arr.length - 1];
			int i = 0;
			for (i = arr.length - 1; i > 0; i--) {
				arr[i] = arr[i - 1];
			}
			arr[i] = tmp;
		} else if (d == -1) {// 반시계
			int tmp = arr[0];
			int i = 0;
			for (i = 0; i < arr.length - 1; i++) {
				arr[i] = arr[i + 1];
			}
			arr[i] = tmp;
		} else {
			// d == 0 do nothing.
		}

	}

}

 

 

	private static void checkChaining(int id, int dir) {
		action = new int[4];
		action[id] = dir;
		
		// 현재 자석에서 오른쪽으로
		for(int i = id + 1 ; i < 4 ; ++i) {
			if(magnet[i][6] != magnet[i - 1][2]) {
				action[i] = action[i - 1] == 1 ? -1 : 1;
			} else {
				action[i] = 0;
				break;
			}
		}
		
		// 현재 자석에서 왼쪽으로
		for(int i = id - 1 ; i >= 0 ; --i) {
			if(magnet[i][2] != magnet[i + 1][6]) {
				action[i] = action[i + 1] == 1 ? -1 : 1;
			} else {
				action[i] = 0;
				break;
			}
		}
	}

'PS > BOJ' 카테고리의 다른 글

5644 무선 충전  (0) 2022.05.16
4014 활주로 탐색  (0) 2022.05.15
2383 점심 식사시간  (0) 2022.05.15
2382 미생물 격리  (0) 2022.05.14
2117 홈 방범 서비스  (0) 2022.05.14
Posted by easy16
PS/BOJ2022. 5. 15. 12:15

 

이번 문제는 해결법을 생각해내지 못했다.

머리속에 Q를 사용하여 각 P를 처리해야될 것 같다까지는 떠올랐지만 실패했다.

이후 구현 방법에 대한 구체가 없어서 검색을 통해 아래의 해결 방법 및 코드를 학습했다.

 

전략

1. 계단이 총2개 존재하므로, 각 계단에 대해 Q를 할당한다.

2. P의 숫자나 맵의 크기가 시간초과가 발생할 정도로 크지 않기 때문에 완전탐색(DFS)을 통해 P가 계단을 선택하는 모든 경우의 수를 시뮬레이션한다. ( 이부분을 전혀 생각해내지 못함, 이 부분만 떠올랐으면 풀어 냈을지도 )

 

3. 각 case에 대한 simulation을 진행한다.

도착시간이 지나고 Q에 빈자리가 생기면 enqueue해준다. 

다음 iteration에서 , 계단을 내려가고 있는 P에 대한 처리를 진행한다. 

계단에 진입한 이후 k시간이 지나면 Q에서 제거, 그렇지 않다면 다시 enqueue해준다.

 

모든 P가 계단에 진입하고(cnt), q1/q2가 empty이면 모든 상황이 종료된다. 

 

유사한 문제가 나왔을 때 활용할 수 있도록 아래의 코드형태를 잘 기억하는게 좋을것 같다.

 

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedList;
import java.util.PriorityQueue;
import java.util.Queue;
import java.util.StringTokenizer;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStreamReader;
import java.io.PrintStream;

class P {
	int x, y;
	int arrivalTime;// 계단 도착시간
	int stair;// 계단 종류
	int stairTime;// 계단을 내려가기 시작한 시각

	P(int x, int y) {
		this.x = x;
		this.y = y;
	}

	public void setArrivalTime(S s) {
		arrivalTime = Math.abs(x - s.x) + Math.abs(y - s.y);
	}

}

class S {
	int x, y, k, cnt;

	S(int x, int y, int k) {
		this.x = x;
		this.y = y;
		this.k = k;
	}
}
class Solution {

	static int N;
	static int[][] map;
	static ArrayList<P> pList;
	static ArrayList<S> sList;
	static boolean[] visited;
	static Queue<P>[] Q;
	private static int ans;

	public static void main(String args[]) throws Exception {

		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

		int T;
		T = Integer.parseInt(br.readLine());

		StringTokenizer st = null;
		StringBuilder sb = new StringBuilder();
		long startTime = System.currentTimeMillis();
		for (int test_case = 1; test_case <= T; test_case++) {
			st = new StringTokenizer(br.readLine());
			N = Integer.parseInt(st.nextToken());
			pList = new ArrayList<>();
			sList = new ArrayList<>();
			for (int i = 0; i < N; i++) {
				st = new StringTokenizer(br.readLine());
				for (int j = 0; j < N; j++) {
					int v = Integer.parseInt(st.nextToken());
					if (v == 1) {
						pList.add(new P(i, j));
					} else if (v != 0) {
						sList.add(new S(i, j, v));
					}
				}
			}

			// init
			ans = Integer.MAX_VALUE;
			Q = new LinkedList[2];
			Q[0] = new LinkedList<>();
			Q[1] = new LinkedList<>();

			go(0);
			System.out.println("#" + test_case + " " + ans);
		}
	}

	private static void go(int level) {

		if (level == pList.size()) {
			visited = new boolean[pList.size()];
			int cur = simulation();
			ans = Math.min(cur, ans);
			return;
		}

		pList.get(level).stair = 0;
		pList.get(level).setArrivalTime(sList.get(0));
		go(level + 1);
		pList.get(level).stair = 1;
		pList.get(level).setArrivalTime(sList.get(1));
		go(level + 1);

	}

	private static int simulation() {
		int cnt = 0;
		int time = 0;

		while (true) {
			// Q안의 P중, 도착시간 + K가 현재시간과 같아지면, 제거한다.
			for (int i = 0; i < 2; i++) {
				int size = Q[i].size();

				for (int j = 0; j < size; j++) {
					P p = Q[i].poll();
					S s = sList.get(i);
					if (p.stairTime + s.k <= time)
						continue;

					Q[i].offer(p);
				}
			}

			if (cnt == pList.size() && Q[0].isEmpty() && Q[1].isEmpty()) {
				return time;
			}

			// Q안에 대기가 3개 미만이면 P를 넣어준다.
			for (int i = 0; i < pList.size(); i++) {
				P p = pList.get(i);
				Queue<P> q = Q[p.stair];
				if (visited[i])
					continue;

				if (p.arrivalTime + 1 <= time && q.size() < 3) {
					visited[i] = true;
					p.stairTime = time;
					q.offer(p);
					cnt++;
				}
			}
			time++;
		}
	}

}

 

 

참조 : https://velog.io/@hyeon930/SWEA-2383-%EC%A0%90%EC%8B%AC-%EC%8B%9D%EC%82%AC%EC%8B%9C%EA%B0%84-Java

'PS > BOJ' 카테고리의 다른 글

4014 활주로 탐색  (0) 2022.05.15
4013 특이한 자석  (0) 2022.05.15
2382 미생물 격리  (0) 2022.05.14
2117 홈 방범 서비스  (0) 2022.05.14
2112 보호필름  (0) 2022.05.14
Posted by easy16
PS/BOJ2022. 5. 14. 23:04

풀이 전략

1. BFS를 사용하며 시간의 흐름(M)를 구분함. (굳이 Q를 사용할 이유는 없다. 그저 내가 편하기 때문에 사용함.)

2. 각 군의 위치를 PriorityQueue에 넣어 매 시간의 흐름마다 위치를 계산함. 이때 계산된 값을 버퍼에 저장하여 다른 각군의 움직임에 따른 개수와 방향을 결정한다. (비효율적이긴 하지만 디버깅할 때는 이점이 있었다.)

 

3. PriorityQueue를 사용 or 정렬을 사용하지 않는다면, 다수의 군이 합쳐지는 경우, 방향이 제대로 결정되지 않아 오답이 나올 수 있다.

 

int Array에 대한 정렬은 아래와 같이 구현 가능하다. (size 및 lambda 식을 인자로 전달하면 된다)

PriorityQueue<int[]> Q = new PriorityQueue<>(4, (a, b) -> {
	return b[2] - a[2];
});

 

 

import java.util.ArrayList;
import java.util.PriorityQueue;
import java.util.StringTokenizer;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStreamReader;
import java.io.PrintStream;

class Solution {

	static int N, M, K;
	static int[][][] map;
	static ArrayList<int[]> list;
	private static boolean DBG = false;
	static int[] dx = { 0, -1, 1, 0, 0 };
	static int[] dy = { 0, 0, 0, -1, 1 };
	static int num;

	public static void main(String args[]) throws Exception {

		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		if (DBG) {
			File file = new File("C:\\Users\\Lee\\eclipse-workspace\\TestApplication\\output.txt");
			PrintStream ps = new PrintStream(new FileOutputStream(file));
			System.setOut(ps);
		}

		int T;
		T = Integer.parseInt(br.readLine());

		StringTokenizer st = null;
		StringBuilder sb = new StringBuilder();
		long startTime = System.currentTimeMillis();
		for (int test_case = 1; test_case <= T; test_case++) {
			st = new StringTokenizer(br.readLine());
			N = Integer.parseInt(st.nextToken());
			M = Integer.parseInt(st.nextToken());
			K = Integer.parseInt(st.nextToken());

			// K개의 군집, 좌표 및 미생물의 수, 방향
			list = new ArrayList<int[]>();
			if (DBG)
				System.out.printf("N : %d M : %d K : %d\n", N, M, K);
			for (int i = 0; i < K; i++) {

				st = new StringTokenizer(br.readLine());
				int r = Integer.parseInt(st.nextToken());
				int c = Integer.parseInt(st.nextToken());
				int n = Integer.parseInt(st.nextToken());
				int d = Integer.parseInt(st.nextToken());

				list.add(new int[] { r, c, n, d });

			}
			num = 0;
			bfs();
			System.out.println("#" + test_case + " " + num);
		}
		if (DBG) {
			long duration = System.currentTimeMillis() - startTime;
			System.out.println("duration : " + duration + "ms");
		}
	}

	static void bfs() {
		PriorityQueue<int[]> Q = new PriorityQueue<>(4, (a, b) -> {
			return b[2] - a[2];
		});

		for (int[] ar : list)
			Q.offer(ar);

		int level = 0;

		while (!Q.isEmpty()) {
			int size = Q.size();
			// 1회 돌 때마다 map을 초기화
			map = new int[N][N][2];
			if (level == M) {
				for (int[] ar : Q) {
					num += ar[2];
				}
				if (DBG)
					System.out.printf("level : %d  M : %d num : %d\n", level, M, num);
				return;
			}

			for (int q = 0; q < size; q++) {
				int[] now = Q.poll();
				int r = now[0], c = now[1], n = now[2], d = now[3];
				int nr = r + dx[d];
				int nc = c + dy[d];
				if (nr == 0 || nr == N - 1 || nc == 0 || nc == N - 1) {
					// 방향 결정
					if (map[nr][nc][0] < n / 2) {
						map[nr][nc][1] = (d % 2 == 0) ? d - 1 : d + 1;
					}
					// 닿은 경우 절반으로 줄임
					map[nr][nc][0] += n / 2;
				} else {
					map[nr][nc][1] = map[nr][nc][0] < n ? d : map[nr][nc][1];
					map[nr][nc][0] += n;
				}

			}

			if (DBG) {
				System.out.println("level : " + level);
				for (int i = 0; i < N; i++) {
					for (int j = 0; j < N; j++) {
						System.out.printf("(%3d %3d) ", map[i][j][0], map[i][j][1]);
					}
					System.out.println();
				}
			}
			for (int i = 0; i < N; i++) {
				for (int j = 0; j < N; j++) {
					if (map[i][j][0] != 0) {
						// if (DBG)
						// System.out.printf("offer %d %d %d %d\n", i, j, map[i][j][0], map[i][j][1]);
						Q.offer(new int[] { i, j, map[i][j][0], map[i][j][1] });
					}
				}
			}

			++level;

		}

	}

}

 

다른 풀이를 보면, 굳이 Queue를 사용할 필요는 없으며 ArrayList 및 for 문 만으로도 구현 가능하다.

 

아래 코드조각을 참조하면 각군에 대해 개별로 처리를 해준 뒤, sort하여 앞뒤 요소를 비교하여 좌표가 같으면 

합쳐준 뒤, 나머지를 삭제한다.

 

				//문자열의 pos 처럼 행렬의 값을 하나로 표시
                virus.num = (virus.i * N) + virus.j;
				
                ...
                
				Collections.sort(list);

                // 이동 후 두 개 이상의 군집이 한 셀에 모이는 경우 군집들이 합쳐지게 된다.
                for (int idx = 0; idx < list.size() - 1; idx++) {
                    Virus now = list.get(idx);
                    Virus next = list.get(idx + 1);
					//같은 위치에 있을 경우, 하나로 합친뒤 나머지를 제거
                    if (now.num == next.num) {
                        now.cnt += next.cnt;
                        list.remove(idx + 1);
                        idx--;
                    }
                }

 

 

 

'PS > BOJ' 카테고리의 다른 글

4013 특이한 자석  (0) 2022.05.15
2383 점심 식사시간  (0) 2022.05.15
2117 홈 방범 서비스  (0) 2022.05.14
2112 보호필름  (0) 2022.05.14
2105 디저트 카페  (0) 2022.05.14
Posted by easy16
PS/BOJ2022. 5. 14. 18:33

 

접근

 

1. K값에 따라 영역이 퍼져나가는 특성이 있으므로 BFS를 통해 해당영역의 home이 몇개인지 count하는 방식으로 문제를 해결함.

 

2. K값의 범위에 대해 고민이 있었다. 처음에 K==N 까지만 탐색하면 모든 맵을 체크할 수 있을거라 지레 짐작 했으나, 마지막 TC에서 하나가 모자란 것을 보고 다시 생각하게 되었다. 2*N과 같이 충분히 크게해서 검사해도 괜찮으나 더 나은 성능을 위해 적당한 값으로 설정했다.

 

3. 다른 사람의 코드를 살펴보니, 미리 저장된 home의 좌표를 활용하여 검사하는 지점으로 부터의 거리 k-1 만큼 떨어지 확인하는 Solution이 있었다. 로직이 단순하고 루프가 적다보니, 확실히 속도 측면에서의 이득이 크다.

 

 

import java.util.LinkedList;
import java.util.Queue;
import java.util.StringTokenizer;
import java.io.BufferedReader;
import java.io.InputStreamReader;

class Solution {

	static int N, M;
	static int[][] map;
	private static boolean DBG = false;

	static int max;
	static int maxIncome;
	static boolean[][] visited;

	public static void main(String args[]) throws Exception {

		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

		// File file = new
		// File("C:\\Users\\Lee\\eclipse-workspace\\TestApplication\\output.txt");
		// PrintStream ps = new PrintStream(new FileOutputStream(file));
		// System.setOut(ps);

		int T;
		T = Integer.parseInt(br.readLine());

		StringTokenizer st = null;
		StringBuilder sb = new StringBuilder();
		long startTime = System.currentTimeMillis();
		for (int test_case = 1; test_case <= T; test_case++) {
			max = Integer.MIN_VALUE;
			st = new StringTokenizer(br.readLine());
			N = Integer.parseInt(st.nextToken());
			M = Integer.parseInt(st.nextToken());

			map = new int[N][N];
			maxIncome = 0;
			for (int i = 0; i < N; i++) {
				st = new StringTokenizer(br.readLine());
				for (int j = 0; j < N; j++) {
					map[i][j] = Integer.parseInt(st.nextToken());
					if (map[i][j] == 1)
						maxIncome += M;
				}
			}

			for (int i = 0; i < N; i++) {
				for (int j = 0; j < N; j++) {
					// K는 임의로 잡았음(범위조절 필요)
					for (int k = 1; k <= N + 3; k++) {

						// 모든 자원보다 k로 인한 비용이 더 큰 경우는 세지 않는다.
						int cost = k * k + (k - 1) * (k - 1);
						if (maxIncome < cost)
							break;

						visited = new boolean[N][N];
						homeCount = 0;
						bfs(i, j, k);

						if (DBG)
							System.out.printf("i,j[%d %d]k : %d cost : %d income :%d homeCount:%d  maxIncome : %d\n", i,
									j, k, cost, homeCount * M, homeCount, maxIncome);
						if (cost <= M * homeCount) {
							max = Math.max(max, homeCount);
						}

					}
				}

			}

			System.out.println("#" + test_case + " " + max);

		}

		System.out.println(sb);

		if (DBG) {
			long duration = System.currentTimeMillis() - startTime;
			System.out.println("duration : " + duration + "ms");
		}

	}

	static int[] dx = { 1, -1, 0, 0 };
	static int[] dy = { 0, 0, 1, -1 };
	static int homeCount;

	private static void bfs(int sr, int sc, int K) {
		Queue<int[]> Q = new LinkedList<>();
		StringBuilder sb = new StringBuilder();
		Q.offer(new int[] { sr, sc });
		int level = 0;
		while (!Q.isEmpty()) {

			int size = Q.size();
			if (level == K) {
				if (DBG)
					System.out.println("K (level) is " + level);
				return;
			}
			for (int q = 0; q < size; q++) {
				int[] now = Q.poll();
				int r = now[0];
				int c = now[1];

				if (visited[r][c])
					continue;
				visited[r][c] = true;

				if (map[r][c] == 1)
					++homeCount;

				for (int i = 0; i < 4; i++) {
					int nr = r + dx[i];
					int nc = c + dy[i];
					if (nr >= 0 && nr < N && nc >= 0 && nc < N && !visited[nr][nc]) {
						Q.offer(new int[] { nr, nc });
					}
				}

			}
			++level;
		}

	}

}

 

참고 코드.

    static int security(int r, int c, int k) {
        int count = 0;
        for(int i=0; i<house.size(); i++) {
            House h = house.get(i);
            if(Math.abs(h.row-r) + Math.abs(h.col - c) <= k-1) count++;
        }
        return count;
    }

 

'PS > BOJ' 카테고리의 다른 글

2383 점심 식사시간  (0) 2022.05.15
2382 미생물 격리  (0) 2022.05.14
2112 보호필름  (0) 2022.05.14
2105 디저트 카페  (0) 2022.05.14
1953 탈주범 검거  (0) 2022.05.13
Posted by easy16