解题思路:本题乍一看好像挺简单,就是个背包问题呗,但是一看要输出字典序最小的路径就懵逼了,所以这个题的难点在于如何记录路径。现在从头开始说,这个题可以看成是一个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;
}
|