-
2024 - 08- 07 C++ 코딩테스트 10주완성 D+28Language Grammar/C++ 2024. 8. 7. 20:49
백준 2636 문제 : 치즈
아래 <그림 1>과 같이 정사각형 칸들로 이루어진 사각형 모양의 판이 있고, 그 위에 얇은 치즈(회색으로 표시된 부분)가 놓여 있다. 판의 가장자리(<그림 1>에서 네모 칸에 X친 부분)에는 치즈가 놓여 있지 않으며 치즈에는 하나 이상의 구멍이 있을 수 있다.
이 치즈를 공기 중에 놓으면 녹게 되는데 공기와 접촉된 칸은 한 시간이 지나면 녹아 없어진다. 치즈의 구멍 속에는 공기가 없지만 구멍을 둘러싼 치즈가 녹아서 구멍이 열리면 구멍 속으로 공기가 들어가게 된다. <그림 1>의 경우, 치즈의 구멍을 둘러싼 치즈는 녹지 않고 ‘c’로 표시된 부분만 한 시간 후에 녹아 없어져서 <그림 2>와 같이 된다.
<그림 1> 원래 치즈 모양 다시 한 시간 후에는 <그림 2>에서 ‘c’로 표시된 부분이 녹아 없어져서 <그림 3>과 같이 된다.
<그림 2> 한 시간 뒤 치즈 모양 <그림 3> 두 시간 뒤 치즈 모양 <그림 3>은 원래 치즈의 두 시간 후 모양을 나타내고 있으며, 남은 조각들은 한 시간이 더 지나면 모두 녹아 없어진다. 그러므로 처음 치즈가 모두 녹아 없어지는 데는 세 시간이 걸린다. <그림 3>과 같이 치즈가 녹는 과정에서 여러 조각으로 나누어 질 수도 있다.
입력으로 사각형 모양의 판의 크기와 한 조각의 치즈가 판 위에 주어졌을 때, 공기 중에서 치즈가 모두 녹아 없어지는 데 걸리는 시간과 모두 녹기 한 시간 전에 남아있는 치즈조각이 놓여 있는 칸의 개수를 구하는 프로그램을 작성하시오.
입력
첫째 줄에는 사각형 모양 판의 세로와 가로의 길이가 양의 정수로 주어진다(세로와 가로의 길이는 최대 100이다.)
판의 각 가로줄의 모양이 윗 줄부터 차례로 둘째 줄부터 마지막 줄까지 주어진다.
치즈가 없는 칸은 0, 치즈가 있는 칸은 1로 주어지며 각 숫자 사이에는 빈칸이 하나씩 있다출력
첫째 줄에는 치즈가 모두 녹아서 없어지는 데 걸리는 시간을 출력한다.
둘째 줄에는 모두 녹기 한 시간 전에 남아있는 치즈조각이 놓여 있는 칸의 개수를 출력한다.실습코드
#include <bits/stdc++.h> using namespace std; //1. 변수 목록 //입력받을 2차원 정수형 배열 a[104][104] //방문한 2차원 정수형 배열 visited[104][104] //가로,세로 길이를 입력받을 정수형 변수 n,m //dfs 탐색을 위한 정수형 배열 dy[4],dx[4] //dfs 탐색을 위한 좌표 정수형 변수 ux,uy; //치즈 녹은 시간을 카운트하는 cnt = 0; //치즈안의 구멍인지 확인할 bool형 변수 isflag = false const int max_n = 104; int a[max_n][max_n]; int visited[max_n][max_n]; int n, m,cnt,ux,uy,c_cnt,b_cnt; int dy[4] = { -1 , 0 , 1 ,0 }; int dx[4] = { 0 , 1 , 0 , -1 }; bool isflag = false; //2-3-1-1 dfs(y,x) //2-3-1-2 visited[y][x] = 1 로 변경후 //2-3-1-3 0 ~ 4까지의 반복문 //2-3-1-3-1 uy = y + dy[i] , ux = x + dx[i] 를 해준후 //2-3-1-3-2 uy >= m 이거나 uy < 0, ux >= n 이거나 ux < 0 이면.. isflag = true 를 하고 continue //2-3-1-3-3 만약 a[uy][ux] == 0 이거나 visitied[uy][ux] == 0 이면 //2-3-1-3-4 dfs(uy,ux) 호출 //2-3-1-3-5 만약 a[uy][ux] == 1 이거나 visited[uy][ux] == 0 이거나 isflag 이면 //2-3-1-3-6 a[uy][ux]++ //2-3-1-3-7 마지막에는 isflag = false 로 해준다. void dfs(int y, int x) { if (visited[y][x] == 2) { visited[y][x] = 1; isflag = true; } for (int i = 0; i < 4; i++) { uy = y + dy[i]; ux = x + dx[i]; if (uy >= n || uy < 0 || ux >= m || ux < 0) { isflag = true; continue; } if (a[uy][ux] == 0 && (visited[uy][ux] == 0 || visited[uy][ux] == 2)) { dfs(uy, ux); } else if (a[uy][ux] == 1 && isflag) { cout << uy << ":" << ux << endl; a[uy][ux]++; visited[uy][ux] = 2; } } } int main() { //핵심 uy ux가 행렬의 값을 넘어서 continue가 걸릴때 무언가 조치를 취해야함 //2. 알고리즘 //2-1 가로 세로 입력받는다. cin >> n >> m; //2-2 가로 세로만큼 반복문 //2-2-1 행렬을 입력받는다. for (int i = 0; i < n; i++) { for (int j = 0; j < m; j++) { cin >> a[i][j]; } } //2-2-2 무한반복 //2-3 가로 세로만큼 반복문 //2-3-1 만약 visited[y][x] == 0 이거나 a[y][x] == 0 이면 dfs(y,x) 호출 while (true) { bool iscontinue = false; for (int i = 0; i < n; i++) { for (int j = 0; j < m; j++) { if (a[i][j] == 0 && (visited[uy][ux] == 0 || visited[uy][ux] == 2)) { dfs(i, j); isflag = false; } } } //2-3-2 가로 세로만큼 반복문 //2-3-2-1 만약 a[uy][ux] == 2 면 a[uy][ux] = 0 으로 바꿔주고 isflag = true 라고 한다. //2-3-2-2 cnt++ 를 해준다. //2-3-2-3 만약 isflag = false 이면 break; for (int i = 0; i < n; i++) { for (int j = 0; j < m; j++) { if (a[i][j] == 2) { c_cnt++; a[i][j] = 0; iscontinue = true; } } } if (iscontinue == false) { cout << cnt << endl << b_cnt; break; } b_cnt = c_cnt; c_cnt = 0; cnt++; } }
내가 짠 코드.. dfs 탐색으로
정수형 배열 a[][] 를 탐색하다가 값이 1인 인덱스에 접근하면
값을 2로 만들고 dfs 탐색을 종료하고 값이 2인 인덱스만 값을 0으로 만들고
치즈 카운트++ 와 전체적인 반복문을 돌릴때마다 cnt++을 하여
치즈가 모두 녹을 때까지 시간과 다 녹기전에 치즈가 얼마나 있는지 확인하는 알고리즘이였다..
하지만 무슨 이유인지 몰라도 안돌아간다 ㅠㅠㅠ.. 강의 실습 코드를 보자..
#include <bits/stdc++.h> using namespace std; int a[104][104], visited[104][104]; int dy[] = {-1,0,1,0}, dx[] = {0,1,0,-1}; int n, m, cnt, cnt2; vector <pair<int,int>>v; void go(int y,int x){ visited[y][x] = 1; if(a[y][x] == 1){ v.push_back({y,x}); return; } for(int i=0; i<4; i++){ int ny = y + dy[i]; int nx = x + dx[i]; if(ny < 0 || ny >= n || nx < 0 || nx >= m || visited[ny][nx])continue; go(ny,nx); } return; } int main(){ cin >> n >> m; for(int i = 0; i < n; i++){ for(int j = 0; j < m; j++){ cin >> a[i][j]; } } while(true){ fill(&visited[0][0], &visited[0][0] + 104 * 104, 0); v.clear(); go(0,0); cnt2 = v.size(); for(pair<int, int> b : v){ a[b.first][b.second] = 0; } bool flag = 0; for(int i = 0; i < n; i++){ for(int j = 0; j < m; j++){ if(a[i][j] != 0) flag = 1; } } cnt++; if(!flag) break; } cout << cnt << '\n' << cnt2 << '\n'; }
나와 비슷한 알고리즘 구조를 가졌지만,
Vector를 이용하여 1의 값을 가진 인덱스의 위치를 저장한 다음
dfs 탐색이 끝난 후 Vector 안에 저장된 위치를 가져와 해당 위치에 있는 원소의 값을 0으로 바꿔준다!
그리고 핵심인 visited 배열을 반복문이 돌때마다 0으로 초기화시켜준다는 것...
아마 저거떄문에 내가 짠 코드가 안돌아갔던것 같다 ㅠㅠ...
진짜 매번 느끼지만 하나의 생각차이로 안돌아갔던게 많았던 만큼 더욱 더 유의하며 알고리즘에 접근해야겠다..
'Language Grammar > C++' 카테고리의 다른 글
2024 - 08- 09 C++ 코딩테스트 10주완성 D+30 (0) 2024.08.09 2024 - 08- 08 C++ 코딩테스트 10주완성 D+29 (0) 2024.08.08 2024 - 08- 06 C++ 코딩테스트 10주완성 D+27 (0) 2024.08.06 2024 - 08- 05 C++ 코딩테스트 10주완성 D+26 (0) 2024.08.05 2024 - 08- 01 C++ 코딩테스트 10주완성 D+25 (0) 2024.08.02