hdu 3033 分组背包(反分组背包)
题意:
3 5 3
1 2 5
2 2 1
3 2 2
第一行有3个数:n v k n 表示有n个物品,v 表示背包容量为v,k表示物品被划分为k类
接下来有n行 每一行有三个数 a b c a 表示该物品属于第a类,b表示该物品的费用,c表示该物品的价值
满足以下条件:1:每个物品最多能拿一次(即01背包) 2:每个类的物品至少拿一个(反分组背包)!!
求满足条件的 最大价值!!若无 输出 Impossible
分析:
每组都进行01背包
dp[i][k]表示第i组 背包容量为k时的最大价值
( 对于第i组物品 第j个物品)有
dp[i][k] = max{ dp[i][k] , max{ dp[i][k-b[i][j].v]+b[i][j].w , dp[i-1][k]+b[i][j].w} }
#include <iostream> #include <cstdio> #include <cstring> using namespace std; int d[11][100001]; int x[11]; struct Node { int v,w; }p[11][101]; int max(int a,int b) { return a>b ? a : b; } int main() { int n,v,k,l,ans; while(~scanf("%d %d %d",&n,&v,&k)) { memset(d,99999,sizeof(d)); ans=d[0][0]=0; memset(x,0,sizeof(x)); for(int i=0;i<n;i++) { scanf("%d",&l); l--; scanf("%d %d",&p[l][x[l]].v,&p[l][x[l]].w ); x[l]++; } for(int j=0;j<x[0];j++) // 用01背包单独处理第一行 for(int c=v;c>=p[0][j].v;c--) d[0][c]=max(d[0][c],d[0][c-p[0][j].v]+p[0][j].w); d[0][0]= d[0][0]==0? -99999999 : d[0][0]; /* 这一句很关键 网上有很多代码 WA 在这一句 其意思是 只要第一行 没有费用为0 价值大于0 的物品 那么第一行的空背包是不可行的一个解 那么我们就给它 赋值为 - ∞ 。 */ for(int i=1;i<k;i++) // 用01背包处理第 (i+1) 行 for(int j=0;j<x[i];j++) for(int c=v;c>=p[i][j].v;c--) d[i][c]=max(d[i][c],max(d[i][c-p[i][j].v]+p[i][j].w,d[i-1][c-p[i][j].v]+p[i][j].w));for(int i=0;i<=v;i++) ans = max(ans,d[k-1][i]); if(ans>0) printf("%d\n",ans); else puts("Impossible"); } return 0; }