做01背包,我们能知道最后的结果,若果求路径,我们可以根据状态转移方程逆推。
看一个百度之星2017年的题
度度熊的午饭时光
对于每组数据,输出两行:第一行输出:"Case #i:"。i代表第i组测试数据。第二行输出菜品的总得分和总花费,以空格分隔。第三行输出所选菜品的序号,菜品序号从1开始,以空格分隔。
这是一个典型的01背包,需要输出路径。
开一个二维数组vis[][],来标记从是否存在从i->j 的状态,在模拟for循环一遍,记录哪些物品被使用过:
for(int i=n;i>=1;--i)
{
if(vis[i][s])
{
pre[i]=true;
s-=c[i];
++k;
}
}
最后for循环一遍,输出状态为true的物品就行了。
#include <iostream>
#include <stdio.h>
#include <string.h>
using namespace std;
const int maxn=105,maxm=1005;
int c[maxn],s[maxn],f[maxm];
bool vis[maxn][maxm],pre[maxn];
int main()
{
int t,n;
scanf("%d",&t);
int b;
for(int cas=1; cas<=t; ++cas)
{
scanf("%d%d",&b,&n);
for(int i=1; i<=n; ++i)
scanf("%d%d",&s[i],&c[i]);
memset(f,0,sizeof(f));
memset(pre,false,sizeof(pre));
memset(vis,false,sizeof(vis));
for(int i=1; i<=n; ++i)
for(int j=b; j>=c[i]; --j)
{
if(f[j]<f[j-c[i]]+s[i])
{
f[j]=f[j-c[i]]+s[i];
vis[i][j]=true;
}
else vis[i][j]=false;
}
int s=b;
int k=0;
for(int i=n; i>=1; --i)
{
if(vis[i][s])
{
pre[i]=true;
s-=c[i];
++k;
}
}
int sum=0;
for(int i=1; i<=n; ++i)
if(pre[i]) sum+=c[i];
printf("Case #%d:\n",cas);
printf("%d %d\n",f[b],sum);
for(int i=1; i<=n; ++i)
if(pre[i])
{
printf("%d",i);
--k;
if(!k) printf("\n");
else printf(" ");
}
}
return 0;
}