Week11 F——东东开车了

东东开车了

东东开车出去泡妞(在梦中),车内提供了 n 张CD唱片,已知东东开车的时间是 n 分钟,他该如何去选择唱片去消磨这无聊的时间呢

假设:

CD数量不超过20张
没有一张CD唱片超过 N 分钟
每张唱片只能听一次
唱片的播放长度为整数
N 也是整数
我们需要找到最能消磨时间的唱片数量,并按使用顺序输出答案(必须是听完唱片,不能有唱片没听完却到了下车时间的情况发生)

Input

多组输入

每行输入第一个数字N, 代表总时间,第二个数字 M 代表有 M 张唱片,后面紧跟 M 个数字,代表每张唱片的时长 例如样例一: N=5,
M=3, 第一张唱片为 1 分钟, 第二张唱片 3 分钟, 第三张 4 分钟

所有数据均满足以下条件:

N≤10000 M≤20

Output

输出所有唱片的时长和总时长,具体输出格式见样例

Sample Input

5 3 1 3 4
10 4 9 8 4 2
20 4 10 5 7 4
90 8 10 23 1 2 3 4 5 7
45 8 4 10 44 43 12 9 8 2

Sample Output

1 4 sum:5
8 2 sum:10
10 5 4 sum:19
10 23 1 2 3 4 5 7 sum:55
4 10 12 9 8 2 sum:45

问题分析

明显是一个0-1背包问题,因为要求输出路径,因此不能用滚动数组。
状态转移方程为:f[i][j] = max(f[i][j], f[i-1][j-w[i]]+v[i]);
输出路径:
f[i][j]是仅考虑将前 i 件物品放入到容量为 j 的背包中能获得的最大价值,则f[i][n]是仅考虑将前 i 件物品放入到容量为n的背包中能获得的最大价值。那么,如果我们选择了第i件物品,则f[i+1][n]应该是f[i][n]+w[i] , 否则应该f[i+1][n].
根据这个思路,我们定义cat数组,0代表不选,1代表选。如果f[i][n] 等于 f[i-1][n]则cat[i]=0,否则cat[i]=1,同时让n减去w[i]。即得到物体是否被选中的数组。
最后按要求输出即可

代码实现

#include<iostream>
#include<algorithm>
using namespace std;

int n, m;
int cd[25];
int f[21][10005];
int ans = 0; 
int cat[25],index=0;

int main()
{
	while(cin>>n>>m)
	{
		for(int i=1; i<=m; i++)
		{
			cin>>cd[i];
		}
		
		for(int i=1; i<=n; i++)
		    f[0][i]  = 0;
		    
		for(int i=1; i<=m; i++)
		{
			for(int j=0; j<=n; j++)
			{
				f[i][j] = f[i-1][j];
				if(j - cd[i] >=0)
				{
					f[i][j] = max(f[i][j], f[i-1][j-cd[i]]+cd[i]);
					
				}
				    
			}
		}
		
		ans = f[m][n];
		for(int i=m; i>1; i--)
		{
			if(f[i][n] == f[i-1][n])
			    cat[i]=0;
			else
			{
				cat[i] = 1;
				n-=cd[i];
			}
		}
		if(f[1][n]>0) cat[1]=1;
		else cat[1]=0;
		
		for(int i=1; i<=m; i++)
		    if(cat[i] == 1)
		        cout<<cd[i]<<" ";
		
		cout<<"sum:"<<ans<<endl;
	}
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值