ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 백준 1699 제곱수의합
    프로그래밍 2021. 2. 13. 23:42
    //두번째로 짰던 코드
    #include<stdio.h>
    
    int n;
    int sqr[1001];
    int dp[100001];
    
    int init(){
    	
    	scanf("%d", &n);
    	
    	int idx;
    	for(int i=1; (i-1)*(i-1) <= n; i++){
    		sqr[i] = i*i;
    		idx = i;
    	}
    	
    	return idx;
    }
    
    int main(){
    
    	//제곱수 sqr배열에 저장. 
    	int idx = init();
    	
    	//dp 초기값
    	dp[1] = 1;
    	
    	//2부터 n까지. 
    	 for(int i=2; i<=n; i++){
    	 	
    	 	int N = i;
    	 	
    	 	int k;
    	 	for(k=1; k<=idx; k++){
    	 		if(sqr[k] > N){
    	 			k = k-1;
    	 			break;
    			}
    		}
    		
    		N -= sqr[k];
    		dp[i]++;
    		dp[i] += dp[N];	
    		
    		
    		N = i;
    		k--;
    		N -= sqr[k];
    		if(dp[N] != 0 && dp[N] + 1 < dp[i]){
    			dp[i] = dp[N] + 1;
    		}
    		
    		
    	}
    	
    	printf("%d", dp[n]);
    
    	return 0;
    }
    

     실버3짜리 dp문제다. 약 3번 트라이후, 방향을 잘못 잡고 있나 싶어서 다른 블로그의 글을 보고 풀었다.

    chanhuiseok.github.io/posts/baek-10/

     

    [백준] 1699번 - 제곱수의 합

    컴퓨터/IT/알고리즘 정리 블로그

    chanhuiseok.github.io

    문제점 : 

    1. 첫번째 시도에서 틀렸다. 반례를 찾았다. 22와 같이 'n보다 작은 자연수 중 가장 큰 제곱수'를 항상 빼버리면 

    22 = 16 + 4 + 1 + 1

    22 = 9 + 9 + 4 와같이, 정답을 못 구하게 된다.

    여기서 착안하여, 'n보다 작은 자연수 중 가장 큰 제곱수 - 1'을 구해서 더 작은 경우 dp값을 업데이트 하는 방법을 썼는데, 당연히 틀렸다. 여기서 갑자기 이상한데로 헤매기 시작했다. 아니, 어느정도 방향은 맞았는데 너무 복잡하게 하고있었다. 재귀함수를 이용하여 top-down식으로 풀었는데, 똑같은 연산을 계속하곤 했다. 사실 여기서 잘못되었다는 것을 눈치챘어야 했는데..

     

    이번 문제를 통해 나름 얻은게 많았다. dp에 대해 더 감이 잡힌듯하다. 잘게 잘게 나누기,, '같은연산'을 반복하는 이유를 파악하고, 해결하기... top-down으로 풀고있는지 한번 의심해보기 등등.. ㅎ

     

     

    //헤메던 3번째코드 - top down - 같은연산반복
    #include <stdio.h>
    
    int sqr[100000];
    int min = 1000000000;
    
    void init(int n) {
        for (int i = 1; i <= n; i++) {
            sqr[i] = i * i;
            if (i * i > n) break;
        }
    }
    
    int findIdx(int n) {
        int largest = 1;
        for (int i = 1; i <= (n / 2 + 1); i++) {
            if (i * i > n) {
                largest = i-1; //idx = n보다 같거나 작은 가장 큰 제곱수 
                break;
            }
        }
        return largest;
    }
    
    void socrates(int n, int i, int d) {
    
        if (d > min) return; //d means depth
    
        n -= sqr[i];
        if (n == 0) {
            if (d < min) {
                min = d;
            }
            return;
        }
    
        int largest = findIdx(n);
        for (int k = largest; k >= 1; k--) {
            socrates(n, k, d + 1);
        }
    }
    
    
    
    int main() {
    
        int n;
        scanf("%d", &n);
    
        init(n);
    
        int largest = findIdx(n);
    
        for (int i = largest; i >= 1; i--) {
            socrates(n, i, 1);
        }
    
        printf("%d", min);
    
        return 0;
    }

     

    // 블로그 보고 풀이한 깰끔 bottom - up 코드
    #include<stdio.h>
    #define min(a,b) a>b ? b : a
    
    int n;
    int sqr[1001];
    int dp[100001];
    
    void init() {
    
    	scanf("%d", &n);
    
    	for (int i = 0; i <= n; i++) {
    		dp[i] = i;
    	}
    }
    
    int main() {
    
    	//제곱수 sqr배열에 저장. 
    	init();
    
    	//dp 초기값
    	dp[1] = 1;
    	dp[2] = 2;
    	dp[3] = 3;
    
    	//2부터 n까지. 
    	for (int i = 4; i <= n; i++) {
    		for (int k = 2; k * k <= i; k++) {
    			dp[i] = min(dp[i], dp[i - k * k] + 1);
    		}
    	}
    
    	printf("%d", dp[n]);
    
    	return 0;
    }
    

    '프로그래밍' 카테고리의 다른 글

    웹시작 하며 배운 새로운 개념  (0) 2021.02.28
    개발자마인드.  (0) 2021.02.23
    인생은 복리다  (0) 2021.02.09
    백준 14405 피카츄  (0) 2021.02.05
    백준 19238 스타트 택시  (0) 2021.02.04
Designed by Tistory.