Koder / 박성훈
article thumbnail

으으 소스가 너무 더러워...!

길이좀 줄여서 보기편하기 하는게 좋은데 소스가 너무 길어서 해독하기 힘들것 같다.

그래도 천천히 설명해보겠다...

https://www.acmicpc.net/problem/14502

 

14502번: 연구소

인체에 치명적인 바이러스를 연구하던 연구소에서 바이러스가 유출되었다. 다행히 바이러스는 아직 퍼지지 않았고, 바이러스의 확산을 막기 위해서 연구소에 벽을 세우려고 한다. 연구소는 크

www.acmicpc.net

#include <stdio.h>

int n,m;
int arr[10][10];
int tmp[10][10];

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

void fill(int x, int y){
	tmp[x][y] = 2;
	for(int i=0; i<4; i++){
		int nx = x + dx[i];
		int ny = y + dy[i];
		if(0<=nx && nx<n && 0<=ny && ny<m && tmp[nx][ny] == 0){
			fill(nx,ny);
		}
	}
	return;
}

int f(int x1,int y1,int x2,int y2,int x3,int y3){
	tmp[x1][y1] = tmp[x2][y2] = tmp[x3][y3] = 1;
	for(int i=0; i<n; i++){
		for(int j=0; j<m; j++){
			if(tmp[i][j] == 2){
				fill(i,j);
			}
		}
	}
	int cnt=0;
	for(int i=0; i<n; i++){
		for(int j=0; j<m; j++){
			if(tmp[i][j] == 0) cnt++;
		}
	}
	return cnt;
}


int main(){
	int max = -1;
	int sum;
	scanf("%d %d", &n, &m);
	for(int i=0; i<n; i++) for(int j=0; j<m; j++) scanf("%d", &arr[i][j]);
	
	for(int x1=0; x1<n; x1++) for(int y1=0; y1<m; y1++){
		if(arr[x1][y1] != 0) continue;
		for(int x2=0; x2<n; x2++) for(int y2=0; y2<m; y2++){
			if(arr[x2][y2] != 0 || (x1==x2&&y1==y2)) continue;
			for(int x3=0; x3<n; x3++) for(int y3=0; y3<m; y3++){
				if(arr[x3][y3] != 0 || (x1==x3&&y1==y3) || (x3==x2&&y3==y2)) continue;
				for(int i=0; i<n; i++) for(int j=0; j<m; j++) tmp[i][j] = arr[i][j];
				sum = f(x1,y1,x2,y2,x3,y3);
				if(max < sum) max = sum;
			}
		}
	}
	printf("%d", max);
	return 0;
}

일단 메인함수부터보자면 안전영역의 최댓값을 반환해야 하므로 max값을 선언해준것을 알 수 있다.

넓이는 무조건 0 이상이니 max는 -1로 시작. sum은 그냥 임시변수.

입력받아야할 값들 전부 입력 받고,

완전 혼돈의 6중 포문이 나오는데 (한줄에 두개씩 겹쳐져있다)

이는 그냥 벽 세개를 새울 좌표를 일일히 전부 확인해본거라 확인하면 쉽다.

여기서 빈곳이 아닌 경우인데 벽을 세우는 경우나, 좌표가 같아 의미없는 경우들을 if문으로 제외해줬고,

f함수는 x1,y1, x2,y2, x3,y3 이 세개의 벽을 세웠을때의 안전영역의 크기를 구하는 함수이다.

 

int f(int x1,int y1,int x2,int y2,int x3,int y3){
	tmp[x1][y1] = tmp[x2][y2] = tmp[x3][y3] = 1;
	for(int i=0; i<n; i++){
		for(int j=0; j<m; j++){
			if(tmp[i][j] == 2){
				fill(i,j);
			}
		}
	}
	int cnt=0;
	for(int i=0; i<n; i++){
		for(int j=0; j<m; j++){
			if(tmp[i][j] == 0) cnt++;
		}
	}
	return cnt;
}

위 소스에서 f함수 부분만 잘라서 보자면

일단 벽을 전부다 세워줬고(1번줄)

이중포문을 돌려 바이러스가 발견되면 fill함수를 실행시키는데,

fill함수는 바이러스를 퍼트리는 함수이다.

바이러스를 모두 퍼트린 후 안전공간의 개수를 그 아래 포문에서 계산해서, 반환해주고 있는데

이게 어떻게 시간초과가 안나는지 계산을 해보면 좀 더 이해하기 쉬울 것 같다.

일단 8*8 크기에서 좌표 3개를 골라야 하므로

8*8*8*8*8*8 = 262144 만큼의 반복이 필요하고, f 함수 내에서 또 최대 64회의 반복이 필요하다.

최대한 간단히 중첩된 포문 수만 세어봤을때 대략 4천만번정도 반복하므로 충분히 시간내에 해결할수 있을거라는 감이 잡힐것이다.

이 문제는 참고로 proofed by AC 기법으로 증명되었으니 걱정하지 않아도 된다 ㅎㅎ

반응형