题解 P1759 【通天之潜水】

wjyyy

2018-04-30 09:53:14

Solution

乍一眼看上去,是一个简单的背包,再一看,原来有2个限制条件。因此我们的数组要开到3维(没有压维做起来比较方便),而且这个题最重要的是要输出路径,这样我们在普通的背包里要进行改进。 首先我们枚举的时候要用到两个参数,其他和01背包一样,并且枚举要从1开始~~(这里卡了我半天)~~。接着我们在更新的时候要存储路径,即$pre[i][j][k]$和$g[i][j][k]$,$pre$数组是存如果这个物品装入背包,那么背包的上一个物品的编号,$g$是存①如果这个物品装入背包,存储它的编号,②如果这个物品不装入背包,存储上一个物品的编号。 这样我们就完成了路径记录和背包过程,最后根据$pre$数组回溯找路径并倒序输出。回溯时也要注意,重力阻力减小了当前物品的值,但回溯时要调用减小前的值,所以加减顺序不要搞错了,这一点在代码里也有标注。 ```cpp #include<cstdio> #include<cstring> int f[101][201][201]; int g[101][201][201]; int pre[101][201][201]; int r[101],p[101],t[101]; int main() { memset(f,0,sizeof(f)); memset(pre,0,sizeof(pre)); int m,v,n; scanf("%d%d%d",&m,&v,&n); for(int i=1;i<=n;i++) { scanf("%d%d%d",&r[i],&p[i],&t[i]); for(int j=0;j<=m;j++) for(int k=0;k<=v;k++) { if(j<r[i]||k<p[i]||f[i-1][j][k]>=f[i-1][j-r[i]][k-p[i]]+t[i]) { f[i][j][k]=f[i-1][j][k]; g[i][j][k]=g[i-1][j][k]; } else { f[i][j][k]=f[i-1][j-r[i]][k-p[i]]+t[i]; pre[i][j][k]=g[i-1][j-r[i]][k-p[i]]; g[i][j][k]=i; } } } printf("%d\n",f[n][m][v]); int x=g[n][m][v],cnt=0; int a[101]; int u; while(pre[x][m][v]!=0) { a[++cnt]=x; x=pre[x][m][v];//回溯调用的是包含当前物品的 m-=r[a[cnt]];//回溯后所用的是不含当前物品的 v-=p[a[cnt]]; } a[++cnt]=x;//模拟栈倒序输出 for(int i=cnt;i>=1;i--) printf("%d ",a[i]); return 0; } ```