芸芸背包

【HDU 2602】 Bone Collector

01背包模版

有个背包,背包有重量上限,有一些不同的骨头,骨头有价值和重量,选一些骨头放进背包,求最大价值。

#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
const int maxn=1010;
const int maxm=1010;
int f[maxm];
struct obj{
    int w,v;
} a[maxn];
int n,V;
int T;
int main(){
    scanf("%d",&T);
    while(T--){
        memset(f,0,sizeof(f));
        scanf("%d%d",&n,&V);
        for(int i=1;i<=n;i++)
        scanf("%d",&a[i].v);
        for(int i=1;i<=n;i++)
        scanf("%d",&a[i].w);

        for(int i=1;i<=n;i++)
        for(int j=V;j>=a[i].w;j--)
        f[j]=max(f[j],f[j-a[i].w]+a[i].v);
        printf("%d\n",f[V]);
    }
}

【HDU 2639】Bone Collector Ⅱ

01背包第K优解

每个f[i]维护一个序列保存其前k优解

#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
const int maxn=110;
const int maxv=1010;
const int maxk=35;
int f[maxv][maxk];
struct obj{
    int v,w;
} a[maxn];
int n,W,T,k;
int x[maxn],y[maxn];
int main(){
    scanf("%d",&T);
    while(T--){
        memset(f,0,sizeof(f));
        memset(x,0,sizeof(x));
        memset(y,0,sizeof(y));

        scanf("%d%d%d",&n,&W,&k);
        for(int i=1;i<=n;i++)
        scanf("%d",&a[i].v);
        for(int i=1;i<=n;i++)
        scanf("%d",&a[i].w);

        for(int i=1;i<=n;i++){
            for(int j=W;j>=a[i].w;j--){
                for(int l=1;l<=k;l++){
                    x[l]=f[j-a[i].w][l]+a[i].v;
                    y[l]=f[j][l];
                }
                for(int p1=1,p2=1,l=1;l<=k&&(p1<=k||p2<=k);){
                    if(x[p1]>y[p2])
                    f[j][l]=x[p1++];
                    else 
                    f[j][l]=y[p2++];
                    if(f[j][l]!=f[j][l-1])l++;
                }
            }
        }
        printf("%d\n",f[W][k]);
    }
}

【HDU 2546】饭卡

01背包变形

用5元买(抢)掉最贵的,剩下的做01背包

#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
const int maxn=1010;
const int maxv=1010;
int f[maxv];
int w[maxn];
int n,m;
int T;
int main(){


    while(scanf("%d",&n)&&n){
        memset(w,0,sizeof(w));
        for(int i=n;i>=1;i--){
            scanf("%d",&w[i]);
            if(w[i]>w[n])swap(w[i],w[n]);
        }
        scanf("%d",&m);
        if(m<5){
            printf("%d\n",m);
            continue;
        }
        memset(f,0,sizeof(f));

        for(int i=1;i<n;i++){
            for(int j=m-5;j>=w[i];j--)
            f[j]=max(f[j],f[j-w[i]]+w[i]);
        }
        printf("%d\n",m-f[m-5]-w[n]);
    }
}

【HDU 1203】I NEED A OFFER!

01背包变形

f[i]表示付出i的代价收不到一份OFFER的概率,做01背包

#include<cstdio>
#include<cstring>
#include<iostream>
#include<cmath>
using namespace std;
const int maxn=10010;
const int maxm=10010;
int w[maxm];
double v[maxm],f[maxn];
int n,m;
double min(double a,double b){
    return a<b?a:b;
}
int main(){
    while(~scanf("%d%d",&n,&m),n+m){
        for(int i=1;i<=m;i++){
            scanf("%d%lf",&w[i],&v[i]);
            v[i]=1.0-v[i];
        }
        for(int i=0;i<=n;i++)f[i]=1.0;

        for(int i=1;i<=m;i++)
        for(int j=n;j>=w[i];j--)
        f[j]=min(f[j],f[j-w[i]]*v[i]);

        printf("%.1f%%\n",(1-f[n])*100);
    }
}

【HDU 2995】Robbieries

01背包变形

f[i]表示抢i元之后能逃脱的概率,做01背包即可

#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
const int maxn=110;
const int maxm=10010;
int w[maxn];
float f[maxm];
float v[maxn];
float p;
int n,m;
int T;
float max(float a,float b){
    return a>b?a:b;
}
int main(){
    scanf("%d",&T);
    while(T--){
        cin>>p>>n;
        p=1-p;
        m=0;
        for(int i=1;i<=n;i++){
            cin>>w[i]>>v[i];
            v[i]=1-v[i];
            m+=w[i];
        }
        memset(f,0,sizeof(f));
        f[0]=1;   
        for(int i=1;i<=n;i++)
        for(int j=m;j>=w[i];j--){
            f[j]=max(f[j],f[j-w[i]]*v[i]);
        }
        for(int i=m;i>=0;i--)
        if(f[i]>p){
            printf("%d\n",i);
            break;
        }
    }
}

【HDU 1114】Piggy-Bank

完全背包变形

已知一些硬币的值和重量,现给出一个重量,求这些硬币可能的值的最小值
f[i]表示重量为i时的价值最小值,做完全背包即可

#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
const int maxn=510;
const int maxm=10010;
const int INF=0x3f3f3f3f;
int T,m,n;
int f[maxm];
int w[maxn],v[maxn];
int main(){
    scanf("%d",&T);
    while(T--){
        int p,q;
        scanf("%d%d",&p,&q);
        m=q-p;
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
        scanf("%d%d",&v[i],&w[i]);

        for(int i=1;i<=m;i++)f[i]=INF;
        f[0]=0;

        for(int i=1;i<=n;i++)
        for(int j=w[i];j<=m;j++)
        f[j]=min(f[j],f[j-w[i]]+v[i]);

        if(f[m]==INF)
        puts("This is impossible.");
        else
        printf("The minimum amount of money in the piggy-bank is %d.\n",f[m]);
    }
}

【HDU 1171】Big Event in HDU

多重背包

把每个物品的数量二进制拆分,然后做01背包

#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
const int maxn=1010;
const int maxm=2555555;
int w[maxn],num[maxn];
int f[maxm];
int n,m,T;
int main(){
    while(scanf("%d",&n)){
        if(n<0)return 0;
        m=0;
        memset(f,0,sizeof(f));

        for(int i=1;i<=n;i++){
            scanf("%d%d",&w[i],&num[i]);
            m+=w[i]*num[i];
        }
        for(int i=1;i<=n;i++){
            int left=num[i];

            for(int k=1;k <= left;k<<=1){
                left-=k;
                int t=w[i]*k;
                for(int j=m/2;j>=t;j--){
                    f[j]=max(f[j],f[j-t]+t);
                }
            }
            if(left>0){
                int t=left*w[i];
                for(int j=m/2;j>=t;j--)
                f[j]=max(f[j],f[j-t]+t);
            }
        }
        int ans1=max(f[m/2],m-f[m/2]);
        int ans2=min(f[m/2],m-f[m/2]);
        printf("%d %d\n",ans1,ans2);
    }
}

【HDU 2191】

多重背包模版

#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
const int maxn=110;
const int maxm=110;
int w[maxm],v[maxm],num[maxm];
int f[maxn];
int n,m,T;
int main(){
    scanf("%d",&T);
    while(T--){
        scanf("%d%d",&n,&m);
        for(int i=1;i<=m;i++){
            scanf("%d%d%d",&w[i],&v[i],&num[i]);
        }
        memset(f,0,sizeof(f));
        for(int i=1;i<=n;i++){
            int left=num[i];
            for(int k=1;k<=left;k<<=1){
                int ww=w[i]*k;
                int vv=v[i]*k;
                left-=k;
                for(int j=n;j>=ww;j--)
                f[j]=max(f[j],f[j-ww]+vv);
            }
            if(left){
                int ww=w[i]*left;
                int vv=v[i]*left;
                for(int j=n;j>=ww;j--)
                f[j]=max(f[j],f[j-ww]+vv);
            }
        }
        int ans=0;
        for(int i=1;i<=n;i++)
        ans=max(ans,f[i]);
        printf("%d\n",ans);
    }
}

【HDU 1059】Dividing

多重背包

给出6种价值不同的物品,每种物品有若干个,问是否能分成总价值相等的两份。
首先总价值为奇数时不可。f[i]表示总价值不超过i时能获得的最大价值。判断f[m/2]==m-f[m/2]即可

#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
const int maxm=120010;
int f[maxm];
int n,T=0,m;
int a[10];
bool read(){
    T++;
    m=0;
    for(int i=1;i<=6;i++){
        scanf("%d",&a[i]);
        m+=a[i]*i;
    }
    return m==0?0:1;
}
void work(){
    printf("Collection #%d:\n",T);
    memset(f,0,sizeof(f));
    for(int i=1;i<=6;i++){
        int left=a[i];
        if(left==0)continue;
        for(int k=1;k<=left;k<<=1){
            int t=i*k;
            left-=k;
            for(int j=m/2;j>=t;j--)
            f[j]=max(f[j],f[j-t]+t);
        }
        if(left){
            int t=i*left;
            for(int j=m/2;j>=t;j--)
            f[j]=max(f[j],f[j-t]+t);
        }
    }
    if(f[m/2]==m-f[m/2])
    puts("Can be divided.");
    else
    puts("Can't be divided.");
    printf("\n");
}
int main(){
    while(read()){
        work();
    }
}

【HDU 2844】Coins

多重背包变形

给出一些硬币的价值和数量,问用这些硬币能组合出1~m中的哪些价值。
用f[i]表示价值i能否被组合出来即可。

#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
const int maxn=110;
const int maxm=100010;
bool f[maxm];
int a[maxn],c[maxn];
int n,m;
int main(){
    while(scanf("%d%d",&n,&m)&&(n+m)){
        for(int i=1;i<=n;i++)
        scanf("%d",&a[i]);
        for(int i=1;i<=n;i++)
        scanf("%d",&c[i]);

        memset(f,0,sizeof(f));
        f[0]=1;
        for(int i=1;i<=n;i++){
            int left=c[i];
            for(int k=1;k<=left;k<<=1){
                int t=a[i]*k;
                left-=k;
                for(int j=m;j>=t;j--)
                f[j]|=f[j-t];
            }
            if(left){
                int t=left*a[i];
                for(int j=m;j>=t;j--)
                f[j]|=f[j-t];
            }
        }
        int ans=0;
        for(int i=1;i<=m;i++)
        if(f[i])ans++;
        printf("%d\n",ans);

    }
}

【HDU 2159】FATE

二维背包

和一维没多大区别。

#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
const int maxn=110;
const int maxm=110;
int f[maxm][maxm];
int n,m,k,s;
int v[maxn],w[maxn];

int main(){
    while(~scanf("%d%d%d%d",&n,&m,&k,&s)){
        for(int i=1;i<=k;i++)
        scanf("%d%d",&v[i],&w[i]); 
        memset(f,0,sizeof(f));

        for(int i=1;i<=k;i++)
        for(int j=w[i];j<=m;j++)
        for(int l=1;l<=s;l++)
        f[j][l]=max(f[j][l],f[j-w[i]][l-1]+v[i]);

        if(f[m][s]<n){
            puts("-1");
        }else{    
            int cost=m;
            for(int i=0;i<=m;i++)
            for(int j=0;j<=s;j++)
            if(f[i][j]>=n)cost=min(i,cost);
            printf("%d\n",m-cost);
        }
    }
}

【HDU 1712】ACboy needs your help

分组背包

ACboy要上M天课,有N种课,每种课上不同天数会获得不同的愉悦度,问ACboy能获得的最大愉悦度。
分组背包上就好了。

#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
const int maxn=110;
const int maxm=10010;
int n,m;
int a[maxn][maxn];
int f[maxm];
int main(){
    while(scanf("%d%d",&n,&m)&&n+m){
        for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
        scanf("%d",&a[i][j]);

        memset(f,0,sizeof(f));

        for(int i=1;i<=n;i++)
        for(int j=m;j>=1;j--)
        for(int k=1;k<=j;k++)
        f[j]=max(f[j],f[j-k]+a[i][k]);

        printf("%d\n",f[m]);
    }
}

【HDU 3033】I live sneakers!

分组背包

有一些鞋属于不同组,每种鞋有一个价格和一个价值,现要用不超过M的钱在每组中买至少一种鞋,且每种鞋最多买一次,求所能获得的最大价值。
f[i,t]表示枚举到第i组鞋,价格之和为t时的最大价值。f[i,t]=max(f[i,t],f[i-1,t-s[i,j].w]+s[i,j].v,f[i,t-s[i,j].w]+s[i,j].v)

#include<cstdio>
#include<cstring>
#include<iostream>
#include<vector>
using namespace std;
const int maxn=110;
const int maxm=10010;
const int maxk=15;
struct obj{
    int w,v;
};

int n,m,k;
int f[maxk][maxm];
int max(int a,int b,int c){
    return max(a,max(b,c));
}
int main(){
    while(~scanf("%d%d%d",&n,&m,&k)){
        vector<obj> s[maxk];
        memset(f,0,sizeof(f));
        for(int i=1;i<=n;i++){
            int a,b,c;
            scanf("%d%d%d",&a,&b,&c);
            s[a].push_back((obj){b,c});
        }

        for(int i=1;i<=k;i++)
        for(int j=0;j<s[i].size();j++)
        for(int t=m;t>=s[i][j].w;t--)
        f[i][t]=max(f[i][t],
        f[i-1][t-s[i][j].w]+s[i][j].v,
        f[i][t-s[i][j].w]+s[i][j].v);


        int ans=0;
        for(int i=1;i<=m;i++)ans=max(ans,f[k][i]);
        if(ans==0)puts("Impossible");
        else printf("%d\n",ans);
    }
}

【HDU 1561】The more,The Better

树形背包

f[u,m]表示在以i为根的子树中选了包括u在内的m个节点所获得的最大价值
f[u,1]=s[u]
f[u,j]=max(f[u,j],f[u,j-k]+f[v,k]) k

#include<cstdio>
#include<cstring>
#include<iostream>
#include<vector>
using namespace std;
const int maxn=210;
int f[maxn][maxn];
int s[maxn];
vector<int> g[maxn];
int n,m;
void DFS(int u,int m){
    int siz=g[u].size();
    f[u][1]=s[u];
    for(int i=0;i<siz;i++){
        int v=g[u][i];
        if(m-1>0)DFS(v,m-1);

        for(int j=m;j>=2;j--)
        for(int k=1;k<j;k++)//k<j保证选了u 
        f[u][j]=max(f[u][j],f[u][j-k]+f[v][k]);
    }
}
int main(){
    while(scanf("%d%d",&n,&m)&&n+m){

        for(int i=0;i<=n;i++)
        g[i].clear();
        memset(f,0,sizeof(f));
        memset(s,0,sizeof(s));

        for(int i=1;i<=n;i++){
            int a,b;
            scanf("%d%d",&a,&b);
            g[a].push_back(i);
            s[i]=b;
        }
        DFS(0,m+1);
        printf("%d\n",f[0][m+1]);
    }
}

【HDU 1011】Starship Troppers

树形背包

给出树上每个节点的bugs数量和可获得能量数,现要在节点上驻扎士兵,每个士兵可以消灭20个bugs,节点上bugs少于20时要驻扎一个士兵。现在有m个士兵,问能获得的最大能量为多少。
f[i,j]表示以i为根的子树中驻扎j个士兵能获得的最大能量,在树上DP即可

#include<cstdio>
#include<cstring>
#include<iostream>
#include<vector>
using namespace std;
const int maxn=110;
const int maxm=110;
int f[maxn][maxm];
int w[maxn],p[maxn];
bool vst[maxn];
int n,m;
vector<int> g[maxn];
void DFS(int u){
    vst[u]=1;
    for(int i=w[u];i<=m;i++)
    f[u][i]=p[u];

    int siz=(int)g[u].size();
    for(int i=0;i<siz;i++){
        int v=g[u][i];
        if(vst[v])continue;
        DFS(v);
        for(int j=m;j>=w[u];j--)
        for(int k=1;k<=j-w[u];k++)
        f[u][j]=max(f[u][j],f[u][j-k]+f[v][k]);
    }
}
int main(){
    while(scanf("%d%d",&n,&m),n+m>0){

        memset(f,0,sizeof(f));
        memset(w,0,sizeof(w));
        memset(p,0,sizeof(p));
        memset(vst,0,sizeof(vst));
        for(int i=1;i<=n;i++)g[i].clear();

        for(int i=1;i<=n;i++){
            scanf("%d%d",&w[i],&p[i]);
            w[i]=(w[i]+19)/20;
        }

        for(int i=1;i<=n-1;i++){
            int u,v;
            scanf("%d%d",&u,&v);
            g[u].push_back(v);
            g[v].push_back(u);
        }
        if(m==0){
            puts("0");
            continue;
        }
        DFS(1);
        printf("%d\n",f[1][m]);
    }
}

你可能感兴趣的:(dp)