以ACWING 12题为例
https://www.acwing.com/problem/content/description/12/
方案输出问题要求从结果遍历
使用了4种方法输出
本题要求的是输出背包方案,并要求方案字典序最小。
因此要从后往前转移,并且等于的时候也要发生转移。
方案1:记录pre[i][j]代表状态(i,j)是否发生了转移。那么一旦pre[i][j]为1,就代表选择了i,就输出i,同时 j 减去背包容积
方案2:即为方案1的递归形式
方案3:记录的的pre[i][j]代表(i,j)状态时候的背包容积。如果背包容积小于j,说明背包发生了转移,输出i。
方案4:直接判断dp[i][j] 与 dp[i + 1][j - v[i]] + w[i] 的 关系。如果相等就说明发生了转移。并且要特判i = n时候的情况,此时只要容积大于v[n],就输出n。
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <iostream>
using namespace std;
const int mod = 1e9 + 7;
vector<int>ans;
int v[1005],w[1005];
int f[1005],pre[1005][1005],pre2[1005][1005];
int dp[1005][1005];
int n,m;
void Print1(int i,int j)
{
if(i == n + 1)return;
if(pre[i][j])
{
printf("%d %d\n",i,j);
Print1(i + 1,j - v[i]);
}
else
{
Print1(i + 1,j);
}
}
void Print2(int num)
{
for(int i = 1;i <= n;i++)
{
if(pre[i][num])
{
printf("%d ",i);
num -= v[i];
}
}
}
void Print3(int i,int j)
{
if(i == n + 1)return;
if(pre2[i][j] < j)
{
printf("%d ",i);
}
Print3(i + 1,pre2[i][j]);
}
void Print4()
{
int j = m;
for(int i = 1;i <= n;i++)
{
if(i == n && j >= v[i])
{
printf("%d\n",i);
break;
}
if(dp[i][j] == dp[i + 1][j - v[i]] + w[i] && j >= v[i])
{
printf("%d ",i);
j -= v[i];
}
}
}
void Zero1()
{
for(int i = n;i >= 1;i--)
{
for(int j = m;j >= 0;j--)
{
pre2[i][j] = j;
if(f[j] <= f[j - v[i]] + w[i] && j >= v[i])
{
pre[i][j] = 1;
f[j] = f[j - v[i]] + w[i];
pre2[i][j] = j - v[i];
}
}
}
}
void Zero2()
{
for(int i = n;i >= 1;i--)
{
for(int j = 0;j <= m;j++)
{
dp[i][j] = dp[i + 1][j];
if(j >= v[i])
{
dp[i][j] = max(dp[i][j],dp[i + 1][j - v[i]] + w[i]);
}
}
}
}
int main()
{
scanf("%d%d",&n,&m);
for(int i = 1;i <= n;i++)
{
scanf("%d%d",&v[i],&w[i]);
}
Zero1();
Zero2();
Print1(1,m);
// Print2(m);
// Print3(1,m);
// Print4();
return 0;
}