ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 1369번 : 배열값
    알고리즘/백준(acmicpc.net) 문제풀이 2022. 1. 22. 14:24
    반응형

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

     

    1369번: 배열값

    첫째 줄에 배열의 크기를 나타내는 자연수 N(2≤N≤1,000)이 주어진다. 둘째 줄부터 N개의 줄에 걸쳐 배열에 적힌 수를 나타내는 정수가 각각 N개씩 빈 칸을 사이에 두고 들어온다. 입력되는 정수는

    www.acmicpc.net

    (1,1) ~ (N,N) 도달 중 만나는 수들을 곱할 때 뒤에 생기는 0의 최솟값을 구하는 문제다.

    아이디어 : 

    뒤에 생기는 0의 개수라는 것은, 곧 2와 5의 개수 중 최솟값이라는 소리다. 따라서 2의 개수와 5의 개수에만 집중해보자.
    최솟값을 구하려면, 2를 최소로 만들거나, 5를 최소로 만들어야 한다. 

    어떤 칸에 도달하려면, 위에서 내려오거나, 왼쪽에서 와야한다.

    여기까지 dp식을 세울 수 있다.
    pair<int,int> dp[2][1001][1001]으로 세울 수 있고,
    dp[0][i][j] : (i,j)칸에 도달했고, 2의 개수를 최소로 만들 때 누적된 2와 5의 개수
    dp[1][i][j] : (i,j)칸에 도달했고, 5의 개수를 최소로 만들 때 누적된 2와 5의 개수
    이렇게 정의할 수 있다.

    dp식을 구하는 방법은 : 
      dp[0][i-1][j]
      dp[1][i-1][j]
      dp[0][i][j-1]
      dp[1][i][j-1]
    이 4가지 방법 중 2의 개수가 가장 작은 것을 dp[0][i][j]에, 5의 개수가 가장 작은 것을 dp[1][i][j]에 넣어주면 된다.

    구현 : 

    우선 나올 수 있는 수인 1~1000000까지 각각 2와 5의 개수만 구해준다.
    만약 어떤 수 i가 2로 나누어 떨어진다면, i의 2의 개수는 i/2의 2의 개수+1이고, i의 5의 개수는 i/2의 5의 개수이다.
    만약 어떤 수 i가 5로 나누어 떨어진다면, i의 2의 개수는 i/5의 2의 개수이고, i의 5의 개수는 i/5의 5의 개수+1이다.

    이중for문을 돌면서 dp값을 다 채우고, dp[0][N][N]과 dp[1][N][N] 중 min(2의개수, 5의개수)가 더 적은 것을 출력한다.

    0을 방문하지 않음에 유의하면서 구현한다.

    코드 : 

    #include <bits/stdc++.h>
    using namespace std;
    using pii=pair<int,int>;
    const int INF=987654231;
    pii cache[1000001];
    int arr[1111][1111];
    pii dp[2][1111][1111];
    pii padd(pii x, pii y){
    	pii ret={x.first+y.first, x.second+y.second};
    	if(ret.first>INF) ret.first=INF;
    	if(ret.second>INF) ret.second=INF;
    	return ret;
    }
    int main(){
    	ios::sync_with_stdio(0); cin.tie(0);
    	int N; cin>>N;
    	for(int i=1; i<=1000000; ++i){
    		if(i%2==0){
    			cache[i]=cache[i/2];
    			cache[i].first++;
    		}
    		else if(i%5==0){
    			cache[i]=cache[i/5];
    			cache[i].second++;
    		}
    	}
    	
    	for(int i=1; i<=N; ++i){
    		for(int j=1; j<=N; ++j){
    			cin>>arr[i][j];
    			if(arr[i][j]==0){
    				continue;
    			}
    			vector<pii> v2; // {0up, 0left, 1up, 1left}
    			vector<pii> v5; // {0up, 0left, 1up, 1left}
    			for(int k=0; k<=1; ++k){
    				if(arr[i-1][j]!=0) v2.push_back(padd(dp[k][i-1][j], cache[arr[i][j]]));
    				if(arr[i-1][j]!=0) v5.push_back(padd(dp[k][i-1][j], cache[arr[i][j]]));
    				if(arr[i][j-1]!=0) v2.push_back(padd(dp[k][i][j-1], cache[arr[i][j]]));
    				if(arr[i][j-1]!=0) v5.push_back(padd(dp[k][i][j-1], cache[arr[i][j]]));
    			}
    			if(i==1 && j==1){
    				v2.push_back(cache[arr[i][j]]);
    				v5.push_back(cache[arr[i][j]]);
    			}
    			if(v2.empty() || v5.empty()){
    				dp[0][i][j]={INF,INF};
    				dp[1][i][j]={INF,INF};
    			}
    			else{
    				sort(v2.begin(), v2.end(), [](pii x, pii y){
    					if(x.first==y.first) return x.second<y.second;
    					return x.first<y.first;
    				});
    				dp[0][i][j]=v2[0];
    				sort(v5.begin(), v5.end(), [](pii x, pii y){
    					if(x.second==y.second) return x.first<y.first;
    					return x.second<y.second;
    				});
    				dp[1][i][j]=v5[0];
    			}
    		}
    	}
    	// for(int i=1; i<=N; ++i){
    	// 	for(int j=1; j<=N; ++j){
    	// 		cout << "dp[0]["<<i<<"]["<<j<<"]="<<dp[0][i][j].first << ", " << dp[0][i][j].second<<'\n';
    	// 		cout << "dp[1]["<<i<<"]["<<j<<"]="<<dp[1][i][j].first << ", " << dp[1][i][j].second<<'\n';
    	// 	}
    	// }
    	int res=min(min(dp[0][N][N].first, dp[0][N][N].second),min(dp[1][N][N].first, dp[1][N][N].second));
    	if(arr[N][N]==0){
    		cout << 0 << '\n';
    	}
    	else{
    		cout << res << '\n';
    	}
    }
    반응형

    '알고리즘 > 백준(acmicpc.net) 문제풀이' 카테고리의 다른 글

    2123번 : 인간 탑 쌓기  (0) 2022.01.29
    1422번 : 숫자의 신  (0) 2022.01.22
    1154번 : 팀 편성  (0) 2022.01.16
    1131번 : 숫자  (0) 2022.01.14
    1125번 : 바닥 장식  (0) 2022.01.12

    댓글

Designed by Tistory.