我最近开始解决DP问题,我遇到了硬币。我尝试使用带有memoization的DP解决它,如果我使用int数组(我猜)它可以正常工作。 这是我的方法(剩下几点修改):
#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 :(得分:3)
限制为n<=10e9
,其数组大小将始终导致内存溢出,因此SIGSEGV
。什么是dp-array的类型并不重要。
您的代码中还有其他错误。首先,有一些测试用例,你必须阅读它们直到EOF。其次,由于限制为10e9
,因此您循环n
次!当然是TLE。
现在,对于递归解决方案,使用memoization:
首先,将答案值保存到数组中的10e6
。将有助于节省时间。可以这样做:
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]);
}
现在,对于任何输入n
,请找到解决方案,
ans = coins(n);
将coins
功能实施为:
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;
}