HDU 3033 I love sneakers! 分组背包+约束限制(每组至少取一个)。

来源:互联网 发布:vc高级编程 编辑:程序博客网 时间:2024/06/05 23:06
 

 注意至少取一个,仔细分析一下,此时光靠一个一维数组是不可以完成状态转移的,必须用二维数组或两个一维数组(滚动数组)。

建议多用二维数组,二维数组比较好理解,不容易出错,除非数据量太大,二维开不下。当然,如果对状态转移理解的比较深刻可以尝试着写成滚动数组。

先讲一讲二维数组的做法:

dp[i][j]表示进行到了第i组容量为j所装载的最大价值。

则dp[i][j]这个状态必须从dp[i-1][j-w[x]]+p[x] (选了第1个第i组的物品),dp[i][j-w[x]]+p[x](已经选过第i组的物品,这次又选了第i组的物品),dp[i][j](不选这个物品);

所以状态转移方程为:

dp[i][j]=max(dp[i][j],max(dp[i][j-w[x]]+p[x],dp[i-1][j-w[x]]+p[x]));

 

二维数组版:

View Code
#include<stdio.h>#include<string.h>#include<algorithm>using namespace std;#define INF 1<<29int n, m, k;int w[101],p[101],z[101];int dp[12][10003];int main(){    int i, j, x;    while(~scanf("%d%d%d",&n,&m,&k))    {        for(i=1;i<=n;i++)            scanf("%d%d%d",&z[i],&w[i],&p[i]);        for(j=0;j<=m;j++)dp[0][j]=0;//最开始层赋0        for(i=1;i<=k;i++)       //其它层赋值-INF            for(j=0;j<=m                dp[i][j]=-INF;        for(i=1;i<=k;i++)            for(x=1;x<=n;x++)                for(j=m;j>=0;j--)                    if(z[x]==i)                        if(j>=w[x])                            dp[i][j]=max(dp[i][j],max(dp[i][j-w[x]]+p[x],dp[i-1][j-w[x]]+p[x]));                            //  如果要写成把2个比较拆开来写的 请注意:                            //下面两个顺序不能换,如果换了,当出现w[x]==0时,会加2次。                            //dp[i][j]=max(dp[i][j],dp[i][j-w[x]]+p[x]);                            //dp[i][j]=max(dp[i][j],dp[i-1][j-w[x]]+p[x]);       if(dp[k][m]<0)printf("Impossible\n");       else printf("%d\n",dp[k][m]);    }    return 0;}

滚动数组版1

View Code
#include<stdio.h>#include<string.h>#include<algorithm>using namespace std;#define INF 1<<29int n, m, k;int w[101],p[101],z[101];int dp[10003],tmp[10003];int main(){    int i, j, x;    while(~scanf("%d%d%d",&n,&m,&k))    {        for(i=1;i<=n;i++)            scanf("%d%d%d",&z[i],&w[i],&p[i]);        memset(dp,0,sizeof(dp));        for(i=1;i<=k;i++)        {            for(j=m;j>=0;j--) //每次状态转移前            {                tmp[j]=dp[j];   //将讲前一轮的状态转移到tmp[]                dp[j]=-INF;        //当前的状态dp[]初始化            }            for(x=1;x<=n;x++)                for(j=m;j>=0;j--)                    if(z[x]==i)                        if(j>=w[x])                            dp[j]=max(dp[j],max(dp[j-w[x]]+p[x],tmp[j-w[x]]+p[x]));       }       if(dp[m]<0)printf("Impossible\n");       else printf("%d\n",dp[m]);    }    return 0;}

 滚动数组版2:

View Code
#include<stdio.h>#include<string.h>#include<algorithm>using namespace std;#define inf 1<<29int n, sum, m;int dp[10003];int z[101], w[101], p[101];int main(){    int i, j, k;    while( ~scanf("%d%d%d", &n, &sum, &m) )    {        for(i = 1; i <= n; i++)            scanf("%d%d%d", &z[i], &w[i], &p[i]);        int g1 = 0, g2 = 1;        for(i = 0; i <= sum; i++)            dp[g1][i] = 0;        for(k = 1; k <= m; k++)        {            for(j = 0; j <= sum; j++)                dp[g2][i] = -inf;            for(j = sum; j >= 0; j--)                for(i = 1; i <= n; i++)                    if(z[i] == k)                    {                        if(w[i] <= j)                            dp[g2][j] = max( dp[g2][j], max ( dp[g2][j - w[i]] + p[i], dp[g1][j - w[i]] + p[i] ) );                    }            g1 = !g1; g2 = !g2;        }        printf("%d\n", dp[g1][sum]);    }    return 0;}

 

 

 

原创粉丝点击