团体程序设计天梯赛 L3-001 凑零钱 (30 分)

本文探讨了解决01背包问题时,如何找到字典序最小的路径,通过先对物品价值降序排序,利用动态规划和pre数组记录路径,详细介绍了关键步骤和代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

解题思路:本题乍一看好像挺简单,就是个背包问题呗,但是一看要输出字典序最小的路径就懵逼了,所以这个题的难点在于如何记录路径。现在从头开始说,这个题可以看成是一个01背包问题,只不过体积和价值都是m罢了,然后要求输出字典序最小的路径,因为要输出字典序最小的路径,所以我们首先要对输入的序列从大到小进行排序,为啥来?因为当我们在做01背包时,如果在后面出现了合法方案会将前面得到的方案给覆盖掉,所以要把越小的数放在越后面,这样求出来的数就是最小字典序方案了,接下来难点来了,如何记录路径?开一个pre[][]数组,如果说当前我们在第i个物品处对体积为j的dp数组(f数组)做了修改,就将pre[i][j]=1,说明在寻找最优解的过程中来到过这一步,然后倒着找走过的状态,然后输出就行,这里不知道怎么用语言来表达QAQ,还是看代码比较好。

上代码:

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
const int N =1E4+10;
int v[N];
int f[110];
int pre[N][110];
int n,m;
bool cmp(int a,int b)
{
	return a>b;
}
int main()
{
	cin>>n>>m;
	for(int i=1;i<=n;i++)
	cin>>v[i];
	sort(v+1,v+1+n,cmp);
	for(int i=1;i<=n;i++)
		for(int j=m;j>=v[i];j--)
		{
			if(f[j]<=f[j-v[i]]+v[i])
			{
				f[j]=f[j-v[i]]+v[i];
				pre[i][j]=1;
			}
		}
	if(f[m]!=m)
	cout<<"No Solution"<<endl;
	else
	{
		bool flag=false;//本题的精华部分 
		for(int i=n,j=m;i>=1&&j>=0;i--)
		{
			if(pre[i][j])
			{
				if(!flag)
				cout<<v[i],flag=true;
				else
				cout<<" "<<v[i];
				j-=v[i];
			}
		}
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值