ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 2024 - 08- 07 C++ 코딩테스트 10주완성 D+28
    Language 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으로 초기화시켜준다는 것...

     

    아마 저거떄문에 내가 짠 코드가 안돌아갔던것 같다 ㅠㅠ...

     

    진짜 매번 느끼지만 하나의 생각차이로 안돌아갔던게 많았던 만큼 더욱 더 유의하며 알고리즘에 접근해야겠다..

Designed by Tistory.