백준 16946번 벽 부수고 이동하기4
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 | #include <iostream> #include <string> #include<cstring> #include<queue> #include <vector> #include <algorithm> #include<cmath> using namespace std; int n, m; int wall[1001][1001]; pair<int,int> ret[1001][1001]; int visited[1001][1001]; int ans[1001][1001]; int Count = 1; //영역의 번호 int cntgd = 1; int dy[4] = { -1,0,1,0 }; int dx[4] = { 0,1,0,-1 }; queue<pair <int, int> > Rmb; void DFS(int y, int x) { //이동했던 장소 기억 visited[y][x] = true; Rmb.push(make_pair(y, x)); for (int i = 0; i < 4; i++) { int nexty = y + dy[i]; int nextx = x + dx[i]; //움직일수 있는 다음 이동장소 범위 만족하고, 방문하지않았으며 //벽이없어서 이동할 수 있는 곳 발견하면 재귀 실행 if (0 <= nexty && nexty < n && 0 <= nextx && nextx < m) { if (!visited[nexty][nextx] && !wall[nexty][nextx]) { Count++; DFS(nexty, nextx); } } } } int main() { ios_base::sync_with_stdio(0); cin.tie(0); cin >> n >> m; vector<string> strwall(n); for (int i = 0; i < n; i++) cin >> strwall[i]; //입력받은 문자열 int형으로 변환 for (int i = 0; i < n; i++) for (int j = 0; j < m; j++) { wall[i][j] = strwall[i][j] - '0'; } for (int i = 0; i < n; i++) { for (int j = 0; j < m; j++) { //벽이 있는 경우 벽을 허물고 이동할 수 있는 개수 카운트 if (wall[i][j] == 0) { Count = 1; DFS(i, j); //영역들이 이동할수있는 영역의 넓이를 ret[i][j].first에 저장해주고 //ret[i][j].second에는 영역의 번호를 지정해준다. while (!Rmb.empty()) { if (ret[Rmb.front().first][Rmb.front().second].first < Count) { ret[Rmb.front().first][Rmb.front().second] = make_pair(Count,cntgd); } Rmb.pop(); } cntgd++; } } } for (int i = 0; i < n; i++) { for (int j = 0; j < m; j++) { //벽이 있는 경우 벽을 허물고 이동할 수 있는 개수 카운트 if (wall[i][j] != 0) { //들린 영역번호 저장하는 벡터 선언 vector<int> ground; //자기 자신을 0으로바꿧을때 움직일수 있는 영역넓이 1부터 시작 int val = 1; for (int k = 0; k < 4; k++) { int nexty = i + dy[k]; int nextx = j + dx[k]; //이동가능한 범위에있는지 체크 //이동한 영역이 이미 들렸던 곳인지 영영번호로 확인하고 //들리지않았다면 영역의 넓이를 더해준다. //그리고 들린 영역의 번호를 들렸다고 표시해줌. if (0 <= nexty && nexty < n && 0 <= nextx && nextx < m) { int a = ret[nexty][nextx].second; bool Check = true; for (int b = 0; b < ground.size(); b++) { //동서남북방향으로 들린 영역의 번호를 저장한 벡터에서 //같은 영역번호가 존재하면? 또 더해줄필요가 없다. if (ground[b] == a) Check = false; } if (Check) { val += ret[nexty][nextx].first; ground.push_back(a); } } } //동서남북 영역 중복되지않게 넓이 모두 더해준 값 ans[i][j]에저장. ans[i][j] = val; } } } for (int i = 0; i < n; i++) { for (int j = 0; j < m; j++) { cout << ans[i][j]%10; } cout << "\n"; } return 0; } | cs |
출처:https://www.acmicpc.net/problem/16946
시간복잡도때문에 애를 먹은 문제입니다.문제를 푸는 방법은
1.주어진 지도의 각 영역넓이를 구해놓는다.
2.벽을 없애고 현위치에서 동서남북방향으로 중복되지않게 구해놓은 영역의 넓이를 더해준다.
였습니다. 밑의 코드는 다른 방식으로 풀었지만 시간복잡도때문에 시간초과가 떴습니다.
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 | #include <iostream> #include <string> #include<cstring> #include<queue> #include <vector> #include <algorithm> #include<cmath> using namespace std; int n, m; int wall[1001][1001]; int ret[1001][1001]; int visited[1001][1001]; int Count=1; int dy[4] = { -1,1,0,0 }; int dx[4] = { 0,0,-1,1 }; void DFS(int y, int x) { //이동했던 장소 기억 visited[y][x] = true; for (int i = 0; i < 4; i++) { int nexty = y + dy[i]; int nextx = x + dx[i]; //움직일수 있는 다음 이동장소 범위 만족하고, 방문하지않았으며 //벽이없어서 이동할 수 있는 곳 발견하면 재귀 실행 if (0 <= nexty && nexty < n && 0 <= nextx && nextx < m) { if (!visited[nexty][nextx]&&!wall[nexty][nextx]) { Count++; DFS(nexty, nextx); } } } } int main() { ios_base::sync_with_stdio(0); cin.tie(0); cin >> n >> m; vector<string> strwall(n); for (int i = 0; i < n; i++) cin >> strwall[i]; //입력받은 문자열 int형으로 변환 for (int i = 0; i < n; i++) for (int j = 0; j < m; j++) wall[i][j] = strwall[i][j] - '0'; for (int i = 0; i < n; i++) { for (int j = 0; j < m; j++) { //벽이 있는 경우 벽을 허물고 이동할 수 있는 개수 카운트 if (wall[i][j] != 0) { //DFS실행 할 때마다 다시 visited 초기화 memset(visited, 0, sizeof(visited)); //본인 위치 1개 부터 시작 Count = 1; //벽 허물기 wall[i][j] = 0; DFS(i, j); //이동가능한 수 저장 ret[i][j] = Count; //계산 끝나고 다시 벽 세우기 wall[i][j] = 1; } } } for (int i = 0; i < n; i++) { for (int j = 0; j < m; j++) { cout << ret[i][j]; } cout << "\n"; } return 0; } | cs |
'알고리즘 > BAEKJOON' 카테고리의 다른 글
백준 2562번 전깃줄 (0) | 2019.04.04 |
---|---|
백준 16766번 Convention (0) | 2019.04.04 |
백준 16771번 Back and Forth (0) | 2019.04.01 |
백준 16770번 The Bucket List (0) | 2019.04.01 |
백준 16769번 Mixing Milk (0) | 2019.04.01 |