现在的位置: 首页 > 综合 > 正文

hdu 3535 经典混合分组背包

2018年04月23日 ⁄ 综合 ⁄ 共 1765字 ⁄ 字号 评论关闭

背景:难!!不看解题报告是绝对想不到。即使看了解题报告的思路再去裸写也有很多误区。。。。真是对思维有很大提升。

思路:用一个二维数组F[i][j]来表示取第i个分组时,背包容量为j所能获得的最大快乐值。

         对于s==0(至少取一个的情况),先把F[i]的值全部设为-INF,这样是为了保证至少选一个。转移方程:F[i][j]=max{F[i][j],max{F[i-1][j-cost[k]+weight[k],F[i][j-cost[k]]+weight[k]}}。当F[i][j-cost[k]]为-INF的时候,这个状态就还没有选背包,显然F[i-1][j-cost[k]]会比它大,就是还没有选背包的时候,一定会选一个。这样保证,对于每一个至少选一个的分组,只有它已经至少选了一个该分组内的背包,才能使状态内值为正值。对于这个分组的下一个分组,也只能用上面的非负值数据,这样就完美的保证了,对于每一个至少选择一个的分组都至少选择了一个。

        对于s==1至多选择一个,先把上一组的数据复制到当前组来,因为里面很可能还要很多-INF的值需要代代相传,才能保证那些至少选一个的组有所选择。总是把F[i][j]更新为在上一组的基础上,选择一个物品的最大值。

       对于s==0任意选,依然先把上一组的数据复制到当前组来,然后01背包。

学习:1.注意把物品循环和限制循环交换只有完全背包,不要太想当然了。

#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
int F[109][109],n,v,cost[109],weight[109],ith;

void free(void){    //make the zeroonebag choose to each thing.
     for(int i=0;i < n;i++)
        for(int j=v;j >= cost[i];j--)
            F[ith][j]=max(F[ith-1][j-cost[i]]+weight[i],max(F[ith][j],F[ith][j-cost[i]]+weight[i]));
}

void atmost1(void){    //like the easy breakteambag.
         for(int j=0;j < n;j++)
             for(int i=v;i >= cost[j];i--)
                 F[ith][i]=max(F[ith][i],F[ith-1][i-cost[j]]+weight[j]);
}

int atleast1(void){
    bool ok=true;
    for(int i=0;i < n;i++) if(cost[i] <= v){ok=false;}
    if(ok) return 0;    //don't satisfy the requirement of boss.
    for(int i=0;i < n;i++){
        for(int j=v;j >= cost[i];j--){
            F[ith][j]=max(F[ith][j],max(F[ith-1][j-cost[i]]+weight[i],F[ith][j-cost[i]]+weight[i]));
        }
    }
    return 1;
}

int main(void){
    int t;
    while(~scanf("%d%d",&t,&v)){
        bool flag=true;
        memset(F,0,sizeof(F));
        for(ith=1;ith <= t;ith++){
            int s;
            scanf("%d%d",&n,&s);
            for(int i=0;i < n;i++) scanf("%d%d",&cost[i],&weight[i]);
            if(s == 1) atmost1();
            else if(s == 2) free();
            else{
                for(int i=0;i <= v;i++) F[ith][i]=-100000000;
                if(atleast1() == 0 && flag){printf("-1\n");flag=false;}
            }
            for(int i=0;i <= v;i++) F[ith+1][i]=F[ith][i];
        }
        if(flag){

            if(F[t][v] < 0) printf("-1\n");
            else printf("%d\n",F[t][v]);
        }
    }
    return 0;
}

【上篇】
【下篇】

抱歉!评论已关闭.