[백준]_16234_인구이동

16234.png 16234.png

`bfs

  • 처음에 너무 어렵게 생각해서 Map이랑 Set을 막 써보다 결국 Map 안에 Set을 넣는 경지까지 이르러버림.
  • 방문 여부를 bfs 안에서 방문 여부랑 전체 방문 여부를 생각했는데 하나만 해줘도 되었다.

처음 짠 코드(1500ms정도)

  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
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.*;

public class Main {
	
	private static class Point{
		int x,y;

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

		@Override
		public int hashCode() {
			final int prime = 31;
			int result = 1;
			result = prime * result + x;
			result = prime * result + y;
			return result;
		}

		@Override
		public boolean equals(Object obj) {
			Point other = (Point) obj;
			if (x != other.x)
				return false;
			if (y != other.y)
				return false;
			return true;
		}
	}
	
	static int N, L, R, nx,ny, cnt=0;
	static boolean flag;
	static int[][] arr, delta = { { 0, 1 }, { 1, 0 }, { 0, -1 }, { -1, 0 } };
	static Set<Point> visited; // bfs 하는 동안 방문 여부
	static Set<Point> global_visited; // 전체 탐색 중 방문 여부
	static Queue<Point> q;
	static Map<Set<Point>, Integer> union; // 방문한 곳과 평균 값 담을 것
	
	public static void main(String[] args) throws IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		StringTokenizer st = new StringTokenizer(br.readLine());
		
		N = Integer.parseInt(st.nextToken());
		L = Integer.parseInt(st.nextToken());
		R = Integer.parseInt(st.nextToken());
		
		arr = new int[N][N];
		for(int i=0;i<N;i++) {
			st = new StringTokenizer(br.readLine());
			for(int j=0;j<N;j++) {
				arr[i][j] = Integer.parseInt(st.nextToken());
			}
		}
		
		while(true) {
			flag = false;
			global_visited = new HashSet<>(); 
			union = new HashMap<>(); 
			
			for(int i=0;i<N;i++) {
				for(int j=0;j<N;j++) {
					if(!global_visited.contains(new Point(i,j))) {
						int get = bfs(i,j);
						if(visited.size()>1)
							union.put(visited,get); //bfs 내 방문한 곳과 평균값 넣기
							global_visited.addAll(visited); // 방문한 곳 전체 표시
					}
				}
			}
			
			if(!flag) break; // bfs 내 거리 조건에 한 번도 들어가지 않았다면 종료
			
			Set<Set<Point>> s = union.keySet();
			Iterator<Set<Point>> iter = s.iterator();
			// 키 값 순회를 위해 iterator 선언 
			while(iter.hasNext()) {
				Set<Point> sp = iter.next();
				int m = union.get(sp);
				for(Point pi : sp) { // 방문한 곳 값 적용
					arr[pi.x][pi.y] = m;
				}
			}
			cnt++;
		}
		
		System.out.println(cnt);
	}

	private static int bfs(int x, int y) {
		int sum = 0, num=0;
		
		visited = new HashSet<>(); // bfs 내 방문여부
		visited.add(new Point(x,y));
	    q = new LinkedList<>();
	    q.offer(new Point(x,y));
	    
	    while(!q.isEmpty()) {
	    	Point p = q.poll();
	    	sum+=arr[p.x][p.y];
	    	num++;
	    	
	    	for(int i=0;i<4;i++) {
	    		nx = p.x+delta[i][0];
	    		ny = p.y+delta[i][1];
	    		if(inside(nx,ny)&&!global_visited.contains(new Point(nx,ny))
	    				&&!visited.contains(new Point(nx,ny))) {
	    			int dist = Math.abs(arr[p.x][p.y] - arr[nx][ny]);
	    			if(dist >=L && dist <=R) {
	    				flag = true;
	    				Point ps = new Point(nx,ny);
	    				q.offer(ps);
	    				visited.add(ps); 
	    				// 거리 조건 만족하면 큐와 방문 set에 넣기
	    			}
	    		}
	    	}
	    }
		return sum/num;
	}

	private static boolean inside(int x, int y) {
		return x >= 0 && x < N && y >= 0 && y < N;
	}
}

새롭게 짠 코드 (664ms 정도)

 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
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.*;

public class B16234 {
	
	private static class Point{
		int x,y;

		public Point(int x, int y) {
			this.x = x;
			this.y = y;
		}
	}
	
	static int N, L, R, nx,ny, cnt=0;
	static boolean flag;
	static int[][] arr, delta = { { 0, 1 }, { 1, 0 }, { 0, -1 }, { -1, 0 } };
	static boolean[][] visited; 
	static Queue<Point> q;
	
	public static void main(String[] args) throws IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		StringTokenizer st = new StringTokenizer(br.readLine());
		
		N = Integer.parseInt(st.nextToken());
		L = Integer.parseInt(st.nextToken());
		R = Integer.parseInt(st.nextToken());
		
		arr = new int[N][N];
		for(int i=0;i<N;i++) {
			st = new StringTokenizer(br.readLine());
			for(int j=0;j<N;j++) {
				arr[i][j] = Integer.parseInt(st.nextToken());
			}
		}
		
		while(true) {
			flag = false;
			visited = new boolean[N][N]; 
			union = new HashMap<>(); 
			
			for(int i=0;i<N;i++) {
				for(int j=0;j<N;j++) {
					if(!visited[i][j]) {
						bfs(i,j);
					}
				}
			}
			
			if(!flag) break;
			cnt++;
		}
		
		System.out.println(cnt);
	}

	private static void bfs(int x, int y) {
		int sum = 0, num=0;
		List<Point> list = new ArrayList<>();
		visited[x][y] = true;
	    q = new LinkedList<>();
	    q.offer(new Point(x,y));
	    
	    while(!q.isEmpty()) {
	    	Point p = q.poll();
	    	sum+=arr[p.x][p.y];
	    	num++;
	    	list.add(new Point(p.x,p.y));
	    	
	    	for(int i=0;i<4;i++) {
	    		nx = p.x+delta[i][0];
	    		ny = p.y+delta[i][1];
	    		if(inside(nx,ny)&&!visited[nx][ny]) {
	    			int dist = Math.abs(arr[p.x][p.y] - arr[nx][ny]);
	    			if(dist >=L && dist <=R) {
	    				flag = true;
	    				Point ps = new Point(nx,ny);
	    				q.offer(ps);
	    				visited[nx][ny] = true; 
	    			}
	    		}
	    	}
	    }
		// 여기서 바로 처리해 버리기
		int average = sum/num;
		for(Point p: list) {
			arr[p.x][p.y] = average;
		}
	}

	private static boolean inside(int x, int y) {
		return x >= 0 && x < N && y >= 0 && y < N;
	}
}
updatedupdated2021-02-262021-02-26
Load Comments?