2016-07-08 5 views
-2

최근에 DP 문제를 해결하기 시작했고 나는 COINS를 발견했습니다. memoization 함께 DP를 사용하여 그것을 해결하기 위해 노력하고 int 배열을 사용하는 경우 잘 작동합니다. 은 여기 내 접근 방식 (왼쪽 약간 수정)입니다 :SPOJ COINS DP 및 재귀 적 접근

#include <stdio.h> 
#include <stdlib.h> 
int dp[100000]; 
long long max(long x, long y) 
{ 
    if (x > y) 
     return x; 
    else 
     return y; 
} 
int main() 
{ 
    int n,i; 
    scanf("%d",&n); 
    dp[0]=0; 
    for(i=1;i<=n;i++) 
    { 
     dp[i]=max(i,dp[i/2] + dp[i/3] + dp[i/4]); 
    } 
    printf("%d\n",dp[n]); 

    return 0; 
} 

그러나 나는 SIGSEGV를 얻을 오래 오래 배열을 사용 나는 즉시 이해하지 않습니다. 필자는 수색을했으며, 내가 이해하지 못하는 재귀 적 해결책이있는 것으로 보인다. 누군가 나를 도와 줄 수 있습니까?

+0

한계는'N <= 10e9', 배열의 크기가 어느 항상 메모리 오버 플로우가 발생합니다 따라서, SIGSEGV 말 :

정확한 코드 (당신이 내 포인트를 얻을). dp-array의 유형이 무엇인지는 중요하지 않습니다. – vish4071

답변

3

한계는 n<=10e9이며, 배열 크기는 항상 메모리 오버플로가 발생하므로 SIGSEGV이됩니다. dp-array의 유형이 무엇인지는 중요하지 않습니다.

코드에 다른 오류가 있습니다. 첫째, 테스트 케이스가 있으며, EOF까지 읽어야합니다. 둘째, 한계가 10e9이므로 n 번 반복됩니다! 틀림없이 TLE.

이제 재귀 솔루션, 메모이 제이션을 사용하여 :

을 첫째, 배열에 10e6까지 답변 값을 저장합니다. 시간을 절약하는 데 도움이됩니다. 으로 수행 할 수 있습니다

ans = coins(n); 

coins 기능을 구현, 모든 입력 n를 들어, 같은 해결책을 찾아,

long long dp[1000000] = {0}; 
for(int i = 1; i < 1000000; i++){ 
    dp[i] = max(i, dp[i/2] + dp[i/3] + dp[i/4]); 
} 

지금과 같은 :

long long coins(long long n){ 
    if (n < 1000000) 
     return dp[n]; 
    return coins(n/2) + coins(n/3) + coins(n/4); 
} 

왜 재귀 솔루션 작품 :

모두 n >= 12에 대한 대답은 ans[n/2] + ans[n/3] + ans[n/4]이 될 것이므로 n > 10e6의 경우 그 답이 반환된다는 것이 분명합니다.

재귀의 기본 조건은 단지 시간을 절약하는 것입니다. 0으로 돌려 줄 수도 있지만, 그런 다음 코너 사례를 처리해야합니다.

#include<stdio.h> 
long long dp[1000000] = {0}; 

long long max(long long a, long long b){ 
    return a>b?a:b; 
} 

long long coins(long long n){ 
    if (n < 1000000) 
     return dp[n]; 
    return coins(n/2) + coins(n/3) + coins(n/4); 
} 

int main(){ 
for(long long i = 1; i < 1000000; i++){ 
    dp[i] = max(i, dp[i/2] + dp[i/3] + dp[i/4]); 
} 
long long n; 
while(scanf("%lld",&n) != EOF){ 
    printf("%lld\n", coins(n)); 
} 
return 0; 
} 
+0

고마워요! 그것은 많은 도움이되었다! 나는 당신에게 연락 할 수있는 곳이나 참조 용으로 솔루션을 볼 수 있을지 궁금합니다. –

+0

또한 n <= 10e9 일 때 재귀 방식을 따르는 것이 일반적인 트릭인가요? 내 재귀 개념은 약간 약하다. –

+0

예 ... 이것은 시간 매니 폴드를 줄입니다. 재귀 깊이를 최소화 할 수 있도록 항상 재귀의 기본 경우를 선택해야합니다. 왜냐하면 재귀는 양날 검이기 때문입니다. 코드 길이를 줄이는 데 도움이되는만큼 재귀 스택이 너무 깊어지면 스택 오버플로가 발생하여 SIGSEGV가 발생합니다. (직접 시도해 보라. spoj의 어떤 그래프 문제라도 DFS를 사용하고 (E, V)에 대한 좋은 한계가있다. 재귀를 시도하면 SO가 발생한다. 반복적으로 동일한 DFS 논리를 구현하면 반복적으로 실행된다.) – vish4071