标签:背包dp
3 3 2 1 2 5 3 8 2 0 1 0 2 1 3 2 4 3 2 1 1 1 3 4 2 1 2 5 3 8 2 0 1 1 2 8 3 2 4 4 2 1 1 1 1 1 1 0 2 1 5 3 2 0 1 0 2 1 2 0 2 2 1 1 2 0 3 2 2 1 2 1 1 5 2 8 3 2 3 8 4 9 5 10
5 13 -1 -1
这道题用的知识比较多,是把三个类型结合起来,让我受益很多。首先用二维状态dp[i][j]表示前i组花费j元获得最多的价值,有三个状态方程,一个是至少一个,一个是至多一个,还有是随意,那么分情况讨论就行了。这里要说一下的是对二维背包,第二和第三种情况都要先把上一行的值继承到这一行来,然后再dp,dp过程中,是对这一行值背包,还是对上一行的值背包,这点要考虑清楚,详细的在代码里了。
#include<stdio.h> #include<string.h> int max(int a,int b){ return a>b?a:b; } struct node{ int w,v; }a[106][106]; int dp[106][106],n1[106],m1[106]; int main() { int n,m,i,j,k; while(scanf("%d%d",&n,&m)!=EOF) { for(i=1;i<=n;i++){ scanf("%d%d",&n1[i],&m1[i]); for(j=1;j<=n1[i];j++){ scanf("%d%d",&a[i][j].w,&a[i][j].v); } } memset(dp,-1,sizeof(dp)); for(i=0;i<=m;i++){ dp[0][i]=0; } for(i=1;i<=n;i++){ if(m1[i]==2){//随便放 for(j=m;j>=0;j--){//先把上一行的值都储存下来 dp[i][j]=dp[i-1][j]; } for(k=1;k<=n1[i];k++){ for(j=m;j>=a[i][k].w;j--){ //if(dp[i-1][j-a[i][k].w]!=-1) //dp[i][j]=max(dp[i][j],dp[i-1][j-a[i][k].w]+a[i][k].v);注意这里不能这么写,因为这里是对i这组内背包,在i组上可以叠加 if(dp[i][j-a[i][k].w]!=-1) dp[i][j]=max(dp[i][j],dp[i][j-a[i][k].w]+a[i][k].v); } } } else if(m1[i]==1){//最多放一个 for(j=m;j>=0;j--){//和上面一样,先等于上一行的值 dp[i][j]=dp[i-1][j]; } for(j=m;j>=0;j--){ for(k=1;k<=n1[i];k++){ if(j>=a[i][k].w && dp[i-1][j-a[i][k].w]!=-1){//这里注意是对i-1这组背包,以为如果 dp[i-1][j-a[i][k].w]==-1,那么转移过来的状态就已经错了,这个状态的值肯定错了,而且这一组只能放一个,不能在组内叠加。 dp[i][j]=max(dp[i][j],dp[i-1][j-a[i][k].w]+a[i][k].v); } } } } else if(m1[i]==0){//至少放一个,这一组不能继承上一行的,以为上一行不为-1的,这一行不一定不为-1,因为这组要放一个以上才成立,和本行有关 for(k=1;k<=n1[i];k++){ for(j=m;j>=a[i][k].w;j--){ if(dp[i][j-a[i][k].w]!=-1){//这里由两个方程转移过来 dp[i][j]=max(dp[i][j],dp[i][j-a[i][k].w]+a[i][k].v); } if(dp[i-1][j-a[i][k].w]!=-1){ dp[i][j]=max(dp[i][j],dp[i-1][j-a[i][k].w]+a[i][k].v); } } } } } printf("%d\n",dp[n][m]); } return 0; }
版权声明:本文为博主原创文章,未经博主允许不得转载。
标签:背包dp
原文地址:http://blog.csdn.net/kirito_acmer/article/details/46726471