HDU 3033

来源:互联网 发布:知乎 努比亚z17和荣耀9 编辑:程序博客网 时间:2024/06/06 14:09

此题我认识到了,巧妙的定义状态,有时可得到更优的方法。

如果枚举每组中选出的情况,情况太多,不行。后来又想对、先01背包求出每个组中每个容量至少选一个的最大值,再对整体进行01背包。容量太大,会超时。

后来想,直接对整体进行01背包就可以了,就和多重背包的01背包解法类似。但是为了保证最后的结果是没个组的至少选一个,所以状态f[]i[j]k][定义对于前i组,前j个物品,容量为k并且每组至少选一个的最大值。可知f[i][j][k]=max(f[i-1][amount[i-1]][k-p[i][j]]+v[i][j],f[i][j-1][k-p[i][j]]+v[i][j],f[i][j-1][k]),滚动数组优化,只要把边界确定好,但是判断的顺序要注意,具体代码注释。

#include <iostream>#include <cstdio>#include <cstring>#include <queue>#include <algorithm>#include <cmath>#include <stack>#include <vector>#define LL long long#define myabs(x) ((x)>0?(x):(-(x)))using namespace std;const int inf=0x3f3f3f3f;int f[12][10000+10];int amount[12];int have[12][100+10];int bra[12][1000+10];int p[100+10],v[100+10];int n,m,kind;int main(){while(~scanf("%d%d%d",&n,&m,&kind)){int i,j,be;memset(amount,0,sizeof(amount));for(i=1;i<=n;i++){scanf("%d%d%d",&be,&p[i],&v[i]);have[be][++amount[be]]=i;}int k,t;memset(f,-inf,sizeof(f));memset(f[0],0,sizeof(f[0]));for(i=1;i<=kind;i++){for(j=1;j<=amount[i];j++){t=have[i][j];for(k=m;k>=p[t];k--){f[i][k]=max(f[i][k-p[t]]+v[t],f[i][k]);//要注意这两行的顺序,如果先判断了下一行,f[i][k]的值就不是存的是f[i][j-1][k],再来判断此句就会出错f[i][k]=max(f[i-1][k-p[t]]+v[t],f[i][k]);}}}if(f[kind][m]>=0) printf("%d\n",f[kind][m]);else printf("Impossible\n");}return 0;                                                                                                }




原创粉丝点击