Week11 作业 F - 东东开车了 UVA - 624
题目描述:
东东开车出去泡妞(在梦中),车内提供了 n 张CD唱片,已知东东开车的时间是 n 分钟,他该如何去选择唱片去消磨这无聊的时间呢
假设:
- CD数量不超过20张
- 没有一张CD唱片超过 N 分钟
- 每张唱片只能听一次
- 唱片的播放长度为整数
- N 也是整数
我们需要找到最能消磨时间的唱片数量,并按使用顺序输出答案(必须是听完唱片,不能有唱片没听完却到了下车时间的情况发生)
本题是 Special Judge
思路:
- 题目很简单,就是01背包,但是要输出路径,但是这里的路径不要求是字典序最小
- 可以直接逆着递推过程去打印方案,没什么问题
- 而且可以发现,下述代码打印的方案不一定是字典序最小的,因为是逆向打印
- 研究了很长时间如何字典序打印路径和为什么逆向打印是不可行的,感觉还是很难理解,我感觉应该再熟悉一下DP然后再来解决打印最小字典序这个问题
总结:
可以按照递推或搜索的过程来逆向打印路径
代码:
#include <cstdio>
#include <iostream>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;
const int MAXN=1e4+5;
int f[25][MAXN];
int w[25]; //w[i]==v[i]
//输出到达 只考虑前i个物品容量为j时最大值 的路径
void print(int i,int j)
{
if(i<=0) return;
if(f[i][j]==f[i-1][j]) //第i个物品没选
{
print(i-1,j);
}
else if( j-w[i]>=0 && f[i][j]==f[i-1][j-w[i]]+w[i]) //第i个物品选了
{
print(i-1,j-w[i]);
cout<<w[i]<<' ';
}
}
int main()
{
int N,M;
while( scanf("%d %d",&N,&M)==2 )
{
memset(f,0,sizeof(f));
for(int i=1;i<=M;i++)
scanf("%d",w+i);
for(int i=1;i<=M;i++)
for(int j=0;j<=N;j++)
{
f[i][j]=f[i-1][j];
if( j>=w[i] )
f[i][j]=max(f[i][j],f[i-1][j-w[i]]+w[i]);
}
print(M,N);
cout<<"sum:"<<f[M][N]<<endl;
}
return 0;
}

浙公网安备 33010602011771号