Study hard

(c++)백준 16234번: 인구 이동 본문

백준/bfs, dfs

(c++)백준 16234번: 인구 이동

Nimgnoej 2020. 10. 15. 22:13

www.acmicpc.net/problem/16234

 

16234번: 인구 이동

N×N크기의 땅이 있고, 땅은 1×1개의 칸으로 나누어져 있다. 각각의 땅에는 나라가 하나씩 존재하며, r행 c열에 있는 나라에는 A[r][c]명이 살고 있다. 인접한 나라 사이에는 국경선이 존재한다. 모��

www.acmicpc.net

[풀이]

문제에 있는 규칙대로 구현하면 되는 문제였다.

구현 순서

1. 국경선 열기

2. 인구 이동

3. 연합 해체, 국경선 닫기

 

1. 국경선 열기

- vector<Country>Union[1250]을 선언하여 사용하였다. (County 구조체는 나라의 위치와 인구수 포함, 1250은 50*50배열에서 나올 수 있는 최대 연합의 수)

- dfs를 이용해서 서로 인접한 나라의 인구 수 차이가 L이상 R이하인 경우 연합을 저장하는 벡터에 넣어줬다. bool check[50][50]을 확인한 나라를 표시하는 데 사용

- 연합 개수 카운트

 

2. 인구 이동

- 연합마다 인구 계산해서 각 나라 인구수 갱신

 

3. 연합 해체, 국경선 닫기

- Union 벡터 clear

- 연합 개수 0으로 초기화

- check 배열 false로 초기화

 

 

#include <iostream>
#include <vector>
#include <cstring>//memset
#include <cstdlib>//abs
using namespace std;

struct Country {
	int x, y;
	int p;//인구 수
};

int N, L, R;
int A[50][50];
int unionCnt;
bool flag = false;
bool check[50][50];//해당 나라가 연합에 포함되어 있는지
const int dx[] = { -1,1,0,0 };//위, 아래
const int dy[] = { 0,0,-1,1 };//왼, 오
vector<Country>Union[1250];//같은 연합에 포함된 나라들 저장 인구수 조정에 사용
//연합은 50*50에서 최대 1250개 나올 수 있음!

void init() {
	memset(check, false, sizeof(check));
	for (int i = 0; i < unionCnt; i++) {
		Union[i].clear();
	}
	unionCnt = 0;
}

void dfs(int x, int y, int u_n) {
	for (int i = 0; i < 4; i++) {
		int nx = x + dx[i];
		int ny = y + dy[i];
		if (nx < 0 || nx >= N || ny < 0 || ny >= N || check[nx][ny])
			continue;
		int d = abs(A[x][y] - A[nx][ny]);
		if (d >= L && d <= R) {
			check[nx][ny] = true;
			Union[u_n].push_back({ nx,ny,A[nx][ny] });
			dfs(nx, ny, u_n);
		}
	}
}

void getUnion() {
	for (int i = 0; i < N; i++) {
		for (int j = 0; j < N; j++) {
			//아직 연합에 속하는지 확인 안 한 나라면
			if (check[i][j] == false) {
				check[i][j] = true;
				dfs(i, j, unionCnt);
				if (!Union[unionCnt].empty()) {
					Union[unionCnt].push_back({ i,j,A[i][j] });
					unionCnt++;
				}
			}
		}
	}
}

void Move() {
	//연합마다 인구 이동
	for (int i = 0; i < unionCnt; i++) {
		//연합 내 전체 인구수
		int All = 0;
		int unionSize = Union[i].size();
		for (int j = 0; j < unionSize; j++) {
			All += Union[i][j].p;
		}
		int np = All / unionSize;
		for (int j = 0; j < unionSize; j++) {
			int x = Union[i][j].x;
			int y = Union[i][j].y;
			A[x][y] = np;
		}
	}
}

void solution() {
	cin >> N >> L >> R;
	int ans = 0;
	for (int i = 0; i < N; i++) {
		for (int j = 0; j < N; j++) {
			cin >> A[i][j];
		}
	}
	while (1) {
		init();
		//연합 구하기, 연합 없으면 끝
		getUnion();
		if (unionCnt>0) {
			Move();
			ans++;
		}
		else
			break;
		/*for (int i = 0; i < N; i++) {
			for (int j = 0; j < N; j++) {
				cout << A[i][j] << ' ';
			}
			cout<<'\n';
		}*/
	}
	cout << ans << '\n';
}

int main() {
	ios_base::sync_with_stdio(false);
	cin.tie(NULL);
	cout.tie(NULL);
	solution();
	return 0;
}

 

※bfs로 푼 코드

 

#include <iostream>
#include <queue>
#include <vector>
#include <cstring>//memset
#include <cmath>//abs
using namespace std;

struct Pos {
	int x, y;
};

int N, L, R;
int A[50][50];
const int dx[] = { -1,1,0,0 };
const int dy[] = { 0,0,-1,1 };
bool check[50][50];
vector<Pos>Union;

void bfs(int startx, int starty) {
	Union.push_back({ startx,starty });
	queue<Pos>q;
	q.push({ startx,starty });
	while (!q.empty()) {
		int x = q.front().x;
		int y = q.front().y;
		q.pop();
		for (int i = 0; i < 4; i++) {
			int nx = x + dx[i];
			int ny = y + dy[i];
			if (nx < 0 || nx >= N || ny < 0 || ny >= N)
				continue;
			//국경선을 공유하는 두 나라의 인구 차이가 L명 이상, R명 이하면
			if (abs(A[x][y] - A[nx][ny]) >= L && abs(A[x][y] - A[nx][ny]) <= R && check[nx][ny] == false) {
				check[nx][ny] = true;
				Union.push_back({ nx,ny });
				q.push({ nx,ny });
			}
		}
	}
}

int getUnion() {
	int t = 0;
	while (1) {
		memset(check, false, sizeof(check));
		bool flag = false;
		for (int i = 0; i < N; i++) {
			for (int j = 0; j < N; j++) {
				if (check[i][j] == true)
					continue;
				check[i][j] = true;
				bfs(i, j);
				//연합이 생겼으면
				if (Union.size() > 1) {
					int p_cnt = 0;
					flag = true;
					int Union_cnt = Union.size();
					for (int u = 0; u < Union_cnt; u++) {
						int x = Union[u].x;
						int y = Union[u].y;
						//연합의 인구수 세기
						p_cnt += A[x][y];
					}
					int np_cnt = p_cnt / Union_cnt;
					for (int u = 0; u < Union_cnt; u++) {
						int x = Union[u].x;
						int y = Union[u].y;
						A[x][y] = np_cnt;
					}
				}
				Union.clear();
			}
		}
		if (flag == false)
			break;
		else t++;
	}
	return t;
}

int main() {
	cin >> N >> L >> R;
	for (int i = 0; i < N; i++) {
		for (int j = 0; j < N; j++) {
			cin >> A[i][j];
		}
	}
	cout << getUnion() << '\n';
	return 0;
}

'백준 > bfs, dfs' 카테고리의 다른 글

(c++)백준 12100번: 2048 (Easy)  (0) 2020.10.16
(c++)백준 13460번: 구슬 탈출 2  (0) 2020.10.16
(c++)백준 15683번: 감시  (0) 2020.10.15
(c++)백준 19238번: 스타트 택시  (0) 2020.10.14
(c++)백준 17406번: 배열 돌리기 4  (0) 2020.10.12