코딩공작소
[백준]연구소3 본문
https://www.acmicpc.net/problem/17142
17142번: 연구소 3
인체에 치명적인 바이러스를 연구하던 연구소에 승원이가 침입했고, 바이러스를 유출하려고 한다. 바이러스는 활성 상태와 비활성 상태가 있다. 가장 처음에 모든 바이러스는 비활성 상태이고, 활성 상태인 바이러스는 상하좌우로 인접한 모든 빈 칸으로 동시에 복제되며, 1초가 걸린다. 승원이는 연구소의 바이러스 M개를 활성 상태로 변경하려고 한다. 연구소는 크기가 N×N인 정사각형으로 나타낼 수 있으며, 정사각형은 1×1 크기의 정사각형으로 나누어져 있다. 연구소는
www.acmicpc.net
너무 억울하다 .... 하루종일 이문제에 매달렸는데 로직자체에는 문제가 없었는데 그냥 answer를 너무 작은값으로
해줘서 오류가 났던거 였다.... answer=1e9로 해주니까 오류가 안났다........... 하 ㅆㅂ.
참고로 1e9는 1*10^9 이다.
먼저, 문제를 읽고 나서 든 생각은 dfs,bfs를 같이 사용해야겠다고 생각했다.
문제의 핵심은 아래와 같다
1.주어진 바이러스들중 M개를 어떻게 선택할 것인지 --> (조합)
-->for문의 시작점을 어떻게 하느냐에 따라서 순열, 조합이 될 수 있다.
2.선택된 바이러스들로 부터 그냥 bfs를 실행해주면 된다.
3.가장 중요한건은 비활성화 바이러스이다. 처음에는 있으나 없으나 라고 생각을 했지만 비활성화 바이러스가
중간에 있느냐, 마지막벽에 있느냐에 따라 시간이 달라지게 된다. 이걸 구현하는게 좀 까다로웠다.
구현 방법은 더이상 전염될 것이 있느냐 없느냐를 구현하는 것이고, 4방향을 탐색할수도 있고 0의 개수를 셀수도 있다.
<초기 코드(좀 번잡함)>
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
|
#include <iostream>
#include <vector>
#include <queue>
#include <cstring>
using namespace std;
struct Birus {
int r;
int c;
bool Alive;
Birus() {};
Birus(int r, int c, bool Alive) :r(r), c(c), Alive(Alive) {};
};
int N, M, cnt=0,answer =
int b_cnt=0;
int map[51][51];
int isV[51][51];
int dr[] = {0,0,1,-1}, dc[] = {1,-1,0,0};
queue<pair<int, int> > q1;
vector<pair<int, int> >start_v;
vector<Birus> birus;
void Show() {
printf("=================================================\n");
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) { if (isV[i][j] == 0) printf("- "); else printf("%d ", isV[i][j] - 1); }
printf("\n");
}
}
int bfs() {
int a,b=b_cnt;
memset(isV, 0, sizeof(isV));
for (int i = 0; i < M; i++) {
q1.push(make_pair(start_v[i].first,start_v[i].second));
isV[start_v[i].first][start_v[i].second]=1; //방문
}
while (!q1.empty()) {
int nr = q1.front().first, nc = q1.front().second;
q1.pop();
a = isV[nr][nc]-1;
for (int i = 0; i < 4; i++) {
int nnr = nr + dr[i], nnc = nc + dc[i];
if (nnr < 0 || nnc < 0 || nnr >= N || nnc >= N) continue;
if (isV[nnr][nnc] == 0 && map[nnr][nnc] == 0) {
q1.push(make_pair(nnr, nnc));
isV[nnr][nnc] = isV[nr][nc] + 1;
b--;
}
else if (isV[nnr][nnc] == 0 && map[nnr][nnc] == 2) { //비활성화바이러스
if (b > 0) { //0이 남아있다면
q1.push(make_pair(nnr, nnc));
isV[nnr][nnc] = isV[nr][nc] + 1;
}
else {
isV[nnr][nnc] = isV[nr][nc];
}
}
}
}
//printf("%d %d\n",a, b);
if (b > 0) return 100;
return a;
}
void dfs(int start,int len) {
if (len == M) {
//bfs gogo
int b = bfs();
//Show();
if (b != 100) {
if (answer >= b) answer = b;
}
if (b == 0) { answer = 500;} ///////이부분이 제일 번잡한거 같다.(스킬부족)
return;
}
for (int i = start; i < birus.size(); i++) {
if (birus[i].Alive == false) {
birus[i].Alive = true;
start_v.push_back(make_pair(birus[i].r,birus[i].c)); //바이러스 선택
dfs(i,len + 1); //뒤로만 진행하기위해서 (순열과 조합의 차이)
birus[i].Alive = false;
start_v.pop_back();
}
}
}
int main()
{
cin >> N >> M;
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
cin >> map[i][j];
if (map[i][j] == 0) b_cnt++; //감염되어야 하는 '0'의 수
if (map[i][j] == 2) { birus.push_back(Birus(i, j, false)); } //바이러스 정보 대입
}
}
dfs(0,0);
if (answer == 1000) printf("-1\n");
else if (answer == 500) printf("0\n");
else printf("%d\n", answer);
return 0;
}
|
cs |
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
|
#include <iostream>
#include <vector>
#include <queue>
#include <cstring>
using namespace std;
struct Birus {
int r;
int c;
bool Alive;
Birus() {};
Birus(int r, int c, bool Alive) :r(r), c(c), Alive(Alive) {};
};
int N, M, cnt=0,answer = 1e9;
int b_cnt=0;
int map[51][51];
int isV[51][51];
int dr[] = {0,0,1,-1}, dc[] = {1,-1,0,0};
queue<pair<int, int> > q1;
vector<pair<int, int> >start_v;
vector<Birus> birus;
int bfs() {
int time,b=b_cnt; //글로벌로 여러번 실행되면 데이터를 해줄때마다 초기화해주어야한다.(까먹기쉬움)
memset(isV, 0, sizeof(isV));
for (int i = 0; i < M; i++) {
q1.push(make_pair(start_v[i].first,start_v[i].second));
isV[start_v[i].first][start_v[i].second]=1; //방문
}
while (!q1.empty()) {
int nr = q1.front().first, nc = q1.front().second;
q1.pop();
time = isV[nr][nc]-1;
for (int i = 0; i < 4; i++) {
int nnr = nr + dr[i], nnc = nc + dc[i];
if (nnr < 0 || nnc < 0 || nnr >= N || nnc >= N) continue;
if (isV[nnr][nnc] == 0 && map[nnr][nnc] == 0) {
q1.push(make_pair(nnr, nnc));
isV[nnr][nnc] = isV[nr][nc] + 1;
b--;
}
else if (isV[nnr][nnc] == 0 && map[nnr][nnc] == 2) { //비활성화바이러스
if (b > 0) { //0이 남아있다면
q1.push(make_pair(nnr, nnc));
isV[nnr][nnc] = isV[nr][nc] + 1;
}
else {
isV[nnr][nnc] = isV[nr][nc];
}
}
}
}
if (b == 0 && answer > time) answer = time; // 모두 탐색했고 최소를 구해준다.
}
void dfs(int start,int len) {
if (len == M) {
//bfs gogo
bfs();
return;
}
for (int i = start; i < birus.size(); i++) {
if (birus[i].Alive == false) {
birus[i].Alive = true;
start_v.push_back(make_pair(birus[i].r,birus[i].c)); //바이러스 선택
dfs(i,len + 1); //뒤로만 진행하기위해서 (순열과 조합의 차이)
birus[i].Alive = false; /// ***dfs재귀의 기본구조***
start_v.pop_back();
}
}
}
int main()
{
cin >> N >> M;
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
cin >> map[i][j];
if (map[i][j] == 0) b_cnt++; //감염되어야 하는 '0'의 수
if (map[i][j] == 2) { birus.push_back(Birus(i, j, false)); } //바이러스 정보 대입
}
}
dfs(0,0);
printf("%d\n", answer == 1e9 ? -1 : answer); //answer이 1e9이면 -1출력 아니면 answer출력
return 0;
}
|
cs |
'알고리즘 > 그래프' 카테고리의 다른 글
[백준]연산자끼워넣기(두번째풂) (0) | 2019.07.29 |
---|---|
[백준]치킨배달 (0) | 2019.07.22 |
[백준]아기상어(두번째풂) (0) | 2019.07.11 |
[백준]인구이동(시간초과..충격) (0) | 2019.07.08 |
[삼성기출]미세먼지...시뮬+탐색 (0) | 2019.07.03 |