Problem Solving/백준

[BOJ/C++] 1736 - 쓰레기 치우기

5-ms 2024. 7. 9. 15:20

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

 


 

알고리즘 동아리 시간에 고민하다가 결국 못풀었던 문제.

처음 고민할땐 DP로 풀릴거같아서 어떻게든 점화식을 세워 보려고 했었는데.. 잘 안되더라;

그리고 점화식 고민하면서 DP인것도 의심이 들었던게, 시간제한이 2초나 되고, N,M이 최대 100밖에 안돼서.. 확신이 안섰다..

(조금 직접적인) 힌트를 들어도 이해가 안됐다가, 다행히 다음날에 번뜩 아이디어가 떠올라서 풀었더니 AC !

 

 

일단, 로봇의 움직임은 문제에서 나왔다시피 아래쪽 또는 오른쪽 둘 중 하나이다.

최소의 로봇을 사용하므로, 하나의 로봇이 최대한 많은 쓰레기를 치워야 한다. 

따라서 모든 쓰레기를 치우기 위해선, 어떤 로봇은 가장 위, 가장 왼쪽에 위치한 쓰레기에 도달해야하고, 그 위치에 도달한 로봇은 로봇의 현재위치 {i,j} ~ {n-1,m-1}에 해당하는 구간에서 가장 위, 가장 왼쪽에 위치한 쓰레기에 마찬가지로 도달해야하고, 마지막으로 {n-1,m-1}에 도달할 것이다. 이렇게 하면 한 로봇이 최대한 많은 쓰레기를 집을 수 있게 된다.

 

그럼 위의 방식으로 재귀적으로 탐색하면 될 것 같다!

여기서 의심이 되는 건 시간복잡도인데, 한 로봇이 치울 수 있는 쓰레기의 최대 개수는 n+m-1. 즉, 최대 재귀 호출 깊이는 n+m-1이고, 재귀함수 내에서 가장 위, 가장 왼쪽 쓰레기를 찾기 위해 O(n*m)시간이 소요된다.(재귀 깊이가 깊어질수록 소요시간이 줄긴 하지만, 조금 넉넉하게 계산해보자.). 그리고 로봇의 최대 수는 min(n,m)개이므로, 

따라서 O( min(n,m) * n*m * (n+m-1) ).

n과 m은 최대 100이니까, 계산해보면 1억 좀 안된다.

시간복잡도 계산을 넉넉하게 계산했으므로 시간내에는 충분히 돌아간다!

 

이 문제로 재귀+그리디 문제는 처음 접해보는 것 같다. 되게 낯선데 문제가 재미있어서 포스팅 해 본다!

 

#include<bits/stdc++.h>
using namespace std;
#define X first
#define Y second
#define rep(i,x,y) for(int i=x;i<y;i++)
#define all(x) begin(x),end(x)
#define rall(x) rbegin(x),rend(x)
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
typedef tuple<int,int,int> tiii;
int dx[] = {0,0,1,-1};
int dy[] = {1,-1,0,0};
/*----------------------*/

int n,m;
int board[101][101];
int cnt;
void f(pii loc){
    rep(i,loc.X,n) rep(j,loc.Y,m){
        if(board[i][j]==1){
            board[i][j] = 0;
            cnt--;
            f({i,j});
            return;
        }
    }
    return;
}

int main(){
    ios::sync_with_stdio(0); cin.tie(0);
    cin>>n>>m;
    rep(i,0,n) rep(j,0,m){
        cin>>board[i][j];
        if(board[i][j]==1) cnt++;
    }

    int ans = 0;
    while(cnt){
        f({0,0});
        ans++;
    }
    cout<<ans<<'\n';

}