我试图通过Codeforces解决问题(http://codeforces.com/problemset/problem/189/A) 这是问题陈述:
Polycarpus有一条带子,长度为n。他希望以满足以下两个条件的方式切割色带:
切割后,每个带状件应具有长度a,b或c。 切割后,带状件的数量应最大。 帮助Polycarpus并找到所需的带状件数量 切割
输入 第一行包含四个空格分隔的整数n,a,b和c(1≤n,a,b,c≤4000) - 相应地,原始色带的长度和切割后的带状件的可接受长度。数字a,b和c可以重合。
输出 打印单个数字 - 最大可能的色带片数。保证至少存在一个正确的色带切割。
示例输入
5 5 3 2
示例输出
2
我尝试使用动态编程(Topdown方法)解决此问题。但我无法得到正确的答案。递归函数可能有问题。这是我的代码:
#include<bits/stdc++.h>
using namespace std;
int n,s;
int a[3];
int val,m=-1;
int dp(int n)
{
if(n==0)
return 0;
for(int i=0;i<3;i++)
{
if(n>=a[i])
{
val=1+dp(n-a[i]);
}
}
if(val>m)
m=val;
return m;
}
int main()
{
scanf("%d %d %d %d",&n,&a[0],&a[1],&a[2]);
cout<<dp(n)<<endl;
return 0;
}
上述方法有什么问题?
答案 0 :(得分:4)
有几个问题:
搜索错误
在你的行中
for(int i=0;i<3;i++)
{
if(n>=a[i])
{
val=1+dp(n-a[i]);
}
}
if(val>m)
m=val;
您应该检查为val
的不同选项获得的不同i
的最大值。
错误终止
如果长度不为0并且没有可以切割色带,则应返回负无穷大等。您当前返回的m
最初为-1(稍后会详细介绍)。这是错误的,对于长条带,基本上确保您只选择a,b和c的最小值。
使用Globals
一些全局变量,例如m
被初始化一次,但是被递归修改。这不是“仅仅”坏的编程习惯 - 它没有做你想要的。
不再使用
通过无条件地调用递归,而不是重复使用以前的调用,您的运行时间不必要地高。
答案 1 :(得分:0)
int main() {
int n, a, b, c;
scanf("%d %d %d %d", &n, &cuts[0], &cuts[1], &cuts[2]);
sort(cuts, cuts + 3);
for (int i = 0; i <= n; i++) {
max_cuts[i] = INT_MIN;
}
max_cuts[0] = 0;
max_cuts[cuts[0]] = 1;
max_cuts[cuts[1]] = 1;
max_cuts[cuts[2]] = 1;
for (int i = 1; i <= n; i++) {
for (int j = 0; j < 3; j++) {
if (cuts[j] > i) break;
max_cuts[i] = max(max_cuts[i - cuts[j]] + 1, max_cuts[i]);
}
}
printf("%d\n", max_cuts[n]);
return 0;
}
答案 2 :(得分:0)
答案 3 :(得分:0)
您可以通过自上而下的方法解决此问题。dp问题始终检查所有可能的情况,然后为我们提供最佳解决方案。因此这是代码
#include<bits/stdc++.h>
using namespace std;
int a,b,c;
int DP[4001];
int solve(int n){
if(n == 0)return 0;
if(n<0) return INT_MIN;
if(DP[n] != -1)return DP[n];
else{
DP[n] = max(1+solve(n-a),max(1+solve(n-b),1+solve(n-c)));
return DP[n];
}
}
int main(){
int n,x;
cin>>n>>a>>b>>c;
for(int i = 0;i<4001;++i){
DP[i] = -1;
}
x = solve(n);
cout<<x;
}