相对复杂的背包问题。首先注意是判断组成总质量-剩下牌总重量的组成。利用类似的判断背包内数字组合的方法,只不过这次不是判断能不能组合而是求组合数目,利用这个数目=0就输出0,>1就输出-1可以AC6个点。对于=1时求牌编号的情况,由于这种情况一定是唯一的,所以我们可以在求组合数目的时候就用fa数组记录下一个质量的上一个质量,用num数组记录这个质量由上一个质量推过来的编号。注意要判断编号被覆盖的情况(例如特例4 3 4 3 3 应当输出2 3结果是3 3)因此如果这个质量已经有了上一个质量的编号就不更新编号了。vector存编号,另外注意要排序把结果按照字典序输出。
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<vector>
using namespace std;
int total,n,sum=0;
int dp[1000010];
int w[110];
int fa[1000010];
int num[110];
int main()
{
cin>>total>>n;
for(int i=1;i<=n;i++)
{
cin>>w[i];
sum+=w[i];
}
total=sum-total;
dp[0]=1;
for(int i=1;i<=n;i++)
for(int j=sum;j>=0;j--)
if(j-w[i]>=0)
{
if(dp[j-w[i]]==1)
{
dp[j]+=dp[j-w[i]];
fa[j]=j-w[i];
if(num[j]==0) num[j]=i;
}
}
vector<int> ans;
if(dp[total]==0) cout<<"0";
if(dp[total]>1) cout<<"-1";
if(dp[total]==1)
{
while(total!=0)
{
ans.push_back(num[total]);
total=fa[total];
}
sort(ans.begin(),ans.end());
for(int i=0;i<ans.size();i++)
{
cout<<ans[i]<<' ';
}
}
return 0;
}