백준/DFS and 백트래킹

[백준 2667] 단지번호붙이기

mintuchel 2023. 5. 13. 14:53

사실 이 문제는 BFS DFS 둘 다 되지만 DFS로 풀어보았다

 


[ 첫번째 시도 ]

int dfs(int starty, int startx) {
	stack<pair<int, int>> s;
	s.push(make_pair(starty, startx));
    
	int y, x, cnt = 0;

	while (!s.empty()) {
		y = s.top().first;
		x = s.top().second;
        
		s.pop(); 
        	map[y][x] = 0; 
        	cnt++;

		if (y + 1 < N && map[y + 1][x]) s.push(make_pair(y + 1, x));
		if (x + 1 < N && map[y][x + 1]) s.push(make_pair(y, x + 1));
		if (y - 1 >= 0 && map[y - 1][x]) s.push(make_pair(y - 1, x));
		if (x - 1 >= 0 && map[y][x - 1]) s.push(make_pair(y, x - 1));
	}
	return cnt;
}

 

맨 처음 만든 함수이다.

 

하지만 이는 치명적인 결함이 있다

바로 중복카운팅이 된다는 것이다

( 방문 경로를 출력해보면 중복되는 경로들이 나온다 )

 

map[y][x] = 0; 을 통해 visited 했다고 map을 최신화하는 작업을 pop 한 뒤에 하게끔 했는데

이러면 중복카운팅이 일어날 수 있다.

 

따라서 stack에 push할때 visited 했다고 최신화를 해줘야한다

 

그래서 map[y][x]=0  코드의 위치만 바꾸면 아래와 같이 나온다

 


[ 두번째 시도 ]

int dfs(int starty, int startx) {
	stack<pair<int, int>> s;
	s.push(make_pair(starty, startx));
	map[starty][startx] = 0; // 시작점은 예외적으로 처리
    
	int y, x, cnt = 0;

	while (!s.empty()) {
		y = s.top().first;
		x = s.top().second;
		
		s.pop();
		cnt++;

		if (y + 1 < N && map[y + 1][x]) { s.push(make_pair(y + 1, x)); map[y+1][x] = 0; }
		if (x + 1 < N && map[y][x + 1]) { s.push(make_pair(y, x + 1)); map[y][x+1] = 0; }
		if (y - 1 >= 0 && map[y - 1][x]) { s.push(make_pair(y - 1, x)); map[y-1][x] = 0; }
		if (x - 1 >= 0 && map[y][x - 1]) { s.push(make_pair(y, x - 1)); map[y][x-1] = 0; }
	}
	return cnt;
}

 

위와 같이 바꾸면 시작점 map[starty][startx] 는 while문 내 if문을 통해 다시 방문되면 안된다

왜냐하면 그렇게 되면 중복처리이기 때문이다.

 

따라서 예외적으로 =0 처리를 해줘야한다

	s.push(make_pair(starty, startx));
	map[starty][startx] = 0; // 시작점은 예외적으로 처리

 

이게 실제로 어떤 문제는 맨 첫번째 코드와 같이 해도 아무 문제가 없다.

하지만 이 문제와 같이 DFS 원소 개수를 카운팅하는 문제는 중복이 있으면 답이 틀릴 수 밖에 없다

 

그래서 최대한 오류가 나지 않는 두 번째 코드로 작성하도록 연습하는게 좋다

 

마지막은 풀코드 ㅇㅇ


[ main ]

#include <iostream>
#include <stack>
#include <vector>
#include <algorithm>

#define SIZE 25

using namespace std;

int map[SIZE][SIZE];
int N;

int dfs(int starty, int startx) {
	stack<pair<int, int>> s;
	s.push(make_pair(starty, startx));
	map[starty][startx] = 0;

	int y, x, cnt = 0;

	while (!s.empty()) {
		y = s.top().first;
		x = s.top().second;
		
		s.pop(); cnt++;

		if (y + 1 < N && map[y + 1][x]) { s.push(make_pair(y + 1, x)); map[y+1][x] = 0; }
		if (x + 1 < N && map[y][x + 1]) { s.push(make_pair(y, x + 1)); map[y][x+1] = 0; }
		if (y - 1 >= 0 && map[y - 1][x]) { s.push(make_pair(y - 1, x)); map[y-1][x] = 0; }
		if (x - 1 >= 0 && map[y][x - 1]) { s.push(make_pair(y, x - 1)); map[y][x-1] = 0; }
	}
	return cnt;
}

int main() {
	ios::sync_with_stdio(0);
	cin.tie(0); cout.tie(0);

	cin >> N;
	char ch;
	vector<int> v;

	for (int i = 0; i < N; i++) {
		for (int k = 0; k < N; k++) {
			cin >> ch; map[i][k] = (int)(ch-'0');
		}
	}

	for (int i = 0; i < N; i++) {
		for (int k = 0; k < N; k++) {
			if (map[i][k]) v.push_back(dfs(i, k));
		}
	}
	
	sort(v.begin(), v.end());
	cout << v.size() << "\n";
	for (auto it = v.begin(); it != v.end(); it++) { cout << *it << "\n"; }
	return 0;
}