zoj 3164 分組揹包 + 各種揹包

把所有的揹包結合起來的一道終極揹包題,做了的話揹包一般就沒問題了

題意:給你n個種類的物品的描述,揹包容量D

每個種類有三個屬性 K E P

K表示這類物品最多可以選多少個,如果爲0表示可以選無限多個

E表示選擇這類物品每個物品的價值

P表示每個物品的花費

如果單純是這樣,那這道題目就太水了,直接多重揹包就ok了

所以題目又加了點,而這一點想了我n久 啊

題目還將一些種類的物品分了個組,每組種類中最多隻能選一個種類的物品

即加上了分組揹包,按理說再往多重揹包上套個分組揹包不久好了,但是仔細想想發現每一組物品是由一些種類的物品組成的,只能在裏面選一類,而每一類物品又有自己的性質,所以不好搞。

做法是這樣的:

開個臨時數組,用來記錄那些被分組種類的物品的狀態,w[i][j]表示第i組物品容量爲j時的最大獲利(相當於預處理)

其他沒被分組的物品直接進行多重揹包就行了

具體見代碼吧(如果對各種揹包不是很瞭解的可以先看看揹包九講)

 

 

 

View Code
#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
using namespace std;
const int maxn = 1500;
const int inf = ~0u>>2;
struct node{
    int K,E,P;
}in[maxn];
int dp[maxn];
int n,m;
char s[100000];
int flag[maxn];
void init(int dp[]){
    fill(dp,dp+m+1,-inf);
    dp[0]=0;
}
void complete(int w,int val,int dp[]){
    for(int i=w;i<=m;i++)if(dp[i-w]>-inf) dp[i]=max(dp[i-w]+val,dp[i]);
}
void zero_one(int w,int val,int dp[]){
    for(int j=m;j>=w;j--)if(dp[j-w]>-inf) dp[j]=max(dp[j-w]+val,dp[j]);
}
int w[10][maxn];
int tmp[maxn];
int main(){
    while(scanf("%d%d",&n,&m)!=EOF){
        for(int i=1;i<=n;i++)scanf("%d%d%d",&in[i].K,&in[i].E,&in[i].P);
        int G;
        scanf("%d",&G);getchar();
        vector<int> group[10];
        memset(flag,0,sizeof(flag));
        for(int i=1;i<=G;i++){
            gets(s);
            int len=strlen(s);
            for(int j=0;j<len;){
                if(s[j]>='1'&&s[j]<='9'){
                    int sum=0;
                    while(s[j]>='0' && s[j] <= '9'){
                        sum=sum*10+s[j]-'0';
                        j++;
                    }
                    flag[sum]=i;
                }
                else j++;
            }
        }
        init(dp);
        for(int i=1;i<=G;i++) init(w[i]);
        for(int i=1;i<=n;i++){
            if(flag[i]) init(tmp);
            if(in[i].K==0 || in[i].K*in[i].P>=m)
                complete(in[i].P,in[i].E,flag[i] ? tmp : dp);
            else {
                int k=1,count=in[i].K;
                while(k<count){
                    zero_one(k*in[i].P,in[i].E*k,flag[i] ? tmp : dp);
                    count-=k;
                    k<<=1;
                }
                zero_one(count*in[i].P,count*in[i].E,flag[i] ? tmp : dp);
            }
            if(flag[i]) for(int j=0;j<=m;j++) w[flag[i]][j]=max(w[flag[i]][j],tmp[j]); 
        }
        for(int i=1;i<=G;i++)
            for(int v=m;v>=0;v--)
                for(int j=0;j<=v;j++)
                    if(dp[v-j] > -inf && w[i][j] > -inf)
                            dp[v]=max(dp[v],dp[v-j]+w[i][j]);
        if(dp[m]>=0) printf("%d\n",dp[m]);
        else printf("i'm sorry...\n");
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章