背包问题--(一本通)课后训练

1.打包

/*一个二维01背包
样例输入: 
6 5 4
10 2 2
20 3 2
40 4 3
30 3 3
样例输出:
50 
*/
#include<iostream>
using namespace std;
#include<cstdio>
#define N 381
int f[N][N];
int n,V,G;
struct Wp{
    int t,v,g;
};
Wp wp[N];
void input()
{
    scanf("%d%d%d",&V,&G,&n);
    for(int i=1;i<=n;++i)
    scanf("%d%d%d",&wp[i].t,&wp[i].v,&wp[i].g);
}
void dp()
{
    for(int i=1;i<=n;++i)
      for(int j=V;j>=wp[i].v;--j)
        for(int k=G;k>=wp[i].g;--k)
        f[j][k]=max(f[j][k],f[j-wp[i].v][k-wp[i].g]+wp[i].t);
    cout<<f[V][G]<<endl;
}
int main()
{
    input();
    dp();
    return 0;
}
View Code

2.砝码称重

#include<iostream>
using namespace std;
#include<cstdio>
int a[7];
bool num[1001]={false};
int main()
{
    for(int i=1;i<=6;++i)
    scanf("%d",&a[i]);
    for(int q=0;q<=a[1];++q)
      for(int w=0;w<=a[2];++w)  
        for(int e=0;e<=a[3];++e)
          for(int r=0;r<=a[4];++r)
            for(int t=0;t<=a[5];++t)
              for(int y=0;y<=a[6];++y)
              {
                  int ll=q*1+w*2+e*3+r*5+t*10+y*20;
                  num[ll]=true;
              }
    int sum=0;
    for(int i=1;i<=1000;++i)
    if(num[i]) sum++;
    cout<<"Total="<<sum<<endl;
    return 0;
 } 
View Code

3.竞赛总分

/*一个简单的完全背包*/
#include<iostream>
using namespace std;
#include<cstdio>
struct Que{
    int tim,fs;
};
int dp[10001];
Que que[10001];
int n,m;
void input()
{
    scanf("%d%d",&m,&n);
    for(int i=1;i<=n;++i)
    scanf("%d%d",&que[i].fs,&que[i].tim);
}

int DP()
{
    for(int i=1;i<=n;++i)
      for(int j=que[i].tim;j<=m;++j)
      dp[j]=max(dp[j],dp[j-que[i].tim]+que[i].fs);
}
int main()
{
    freopen("inflate.in","r",stdin);
    freopen("inflate.out","w",stdout);
    input();
    DP();
    printf("%d\n",dp[m]);
    fclose(stdin);
    fclose(stdout);
    return 0;
}
View Code

 4.最小乘车费用

 时间限制: 1 s
 空间限制: 256000 KB
 题目等级 : 黄金 Gold
题目描述 Description

假设某条街上每一公里就有一个公共汽车站,并且乘车费用如下:

公里数   1    2    3    4    5     6    7     8     9    10

费用      12  21  31  40  49  58  69   79   90   101

任意一辆汽车从不行驶超过10公里。某人想行驶n公里,可以任意次换车,请帮他找到一种乘车方案,使得费用最小。

注意:10公里的费用是可以比1公里小的。

输入描述 Input Description

输入文件共两行,

第一行为10个不超过200的整数,依次表示1~10公里的费用。

第二行为某人想要行驶的公里数。

输出描述 Output Description

输出仅一行,为乘车的最小费用。

样例输入 Sample Input

12 21 31 40 49 58 69 79 90 101

15

样例输出 Sample Output

147

/*一个恰好装满的完全背包,因为是求最小值,就把f[i]=大数,f[0]=0这样只有刚好走到,才更新*/
#include<iostream>
using namespace std;
#include<cstdio>
#define N 100001
struct Lc{
    int len,fare;
};
Lc lc[11];
int f[N],n;
#include<cstring>
void input()
{
    for(int i=1;i<=10;++i)
    {
        scanf("%d",&lc[i].fare);
        lc[i].len=i;
    }
    scanf("%d",&n);
}
void dp()
{
    memset(f,99,sizeof(f));
    f[0]=0;
    for(int i=1;i<=10;++i)
      for(int j=lc[i].len;j<=n;++j)
      f[j]=min(f[j],f[j-lc[i].len]+lc[i].fare);
    cout<<f[n]<<endl;
}
int main()
{
    input();
    dp();
    return 0;
}
View Code

5.逃亡的准备

/*多重背包的二进制拆分*/
#include<iostream>
using namespace std;
#include<cstdio>
#define N 2001
#define V 501
int n,vv;
struct Wp{
    int v,val;
}; 
Wp wp[N];
int f[V],t=0;
void input()
{
    scanf("%d%d",&n,&vv);
    int cou,v1,val1;
    for(int i=1;i<=n;++i)
    {
        scanf("%d%d%d",&cou,&v1,&val1);
        if(cou==1)
        {
            ++t;
            wp[t].v=v1;
            wp[t].val=val1;
            
            continue;
        }
        for(int j=1;j<=cou;j<<=1)
        {
            ++t;
            wp[t].v=j*v1;
            wp[t].val=j*val1;
            cou-=j;
        }
        if(cou>0)
        {
            ++t;
            wp[t].v=cou*v1;
            wp[t].val=cou*val1;
        }
    }
}
void DP()
{
    for(int i=1;i<=t;++i) 
      for(int j=vv;j>=wp[i].v;--j)
       f[j]=max(f[j],f[j-wp[i].v]+wp[i].val);
    cout<<f[vv]<<endl;
}
int main()
{
    freopen("hallows.in","r",stdin);
    freopen("hallows.out","w",stdout);
    input();
    DP();
    fclose(stdin);
    fclose(stdout);
    return 0;
}
View Code

6.暗黑游戏

/*多重背包的三循环做法*/
#include<iostream>
using namespace std;
#include<cstdio>
int n,P,R;
struct Wp{
    int p,r,count,zd;
};
Wp wp[151];
int dp[101][101];
void input()
{
    scanf("%d%d%d",&n,&P,&R);
    for(int i=1;i<=n;++i)
    {
        cin>>wp[i].p>>wp[i].r>>wp[i].count>>wp[i].zd;
        
    }
    
}
void DP()
{
    for(int i=1;i<=n;++i)
    {
        if(wp[i].count==0)
        {
            for(int j=wp[i].r;j<=R;++j)
              for(int k=wp[i].p;k<=P;++k)
                for(int s=0;s<=wp[i].count;++s)
                if(j-s*wp[i].r>=0&&k-s*wp[i].p>=0)
              dp[j][k]=max(dp[j][k],dp[j-s*wp[i].r][k-s*wp[i].p]+s*wp[i].zd);
                 else break;
        }
        else 
        {
            for(int j=R;j>=wp[i].r;--j)
              for(int k=P;k>=wp[i].p;--k)
               for(int s=0;s<=wp[i].count;++s)
               if(j-s*wp[i].r>=0&&k-s*wp[i].p>=0)
              dp[j][k]=max(dp[j][k],dp[j-s*wp[i].r][k-s*wp[i].p]+s*wp[i].zd);
                else break;
        }
    }
}
int main()
{
    freopen("pgrune.in","r",stdin);
    freopen("pgrune.out","w",stdout);
    //ios::sync_with_stdio(false);/*加上这句结构体就没有了值*/
    input();
    DP();
    cout<<dp[R][P]<<endl;
    fclose(stdin);
    fclose(stdout);
    return 0;
}
View Code

7.潜水员(必须拿够的背包问题)

【例5】潜水员
问题描述
w    潜水员为了潜水要使用特殊的装备。他有一个带2种气体的气缸:一个为氧气,一个为氮气。让潜水员下潜的深度需要各种的数量的氧和氮。潜水员有一定数量的气缸。每个气缸都有重量和气体容量。潜水员为了完成他的工作需要特定数量的氧和氮。他完成工作所需气缸的总重的最低限度的是多少?
w    例如:潜水员有5个气缸。每行三个数字为:氧,氮的(升)量和气缸的重量:
w    3 36 120
w    10 25 129
w    5 50 250
w    1 45 130
w    4 20 119
w    如果潜水员需要5升的氧和60升的氮则总重最小为249(1,2或者4,5号气缸)。
w    你的任务就是计算潜水员为了完成他的工作需要的气缸的重量的最低值。
【输入格式】
w  第一行有2整数m,n(1<=m<=21,1<=n<=79)。它们表示氧,氮各自需要的量。
w  第二行为整数k(1<=n<=1000)表示气缸的个数。
w  此后的k行,每行包括ai,bi,ci(1<=ai<=21,1<=bi<=79,1<=ci<=800)3整数。这些各自是:第i个气缸里的氧和氮的容量及汽缸重量。
【输出格式】
w  仅一行包含一个整数,为潜水员完成工作所需的气缸的重量总和的最低值。
 
/*必须拿够的背包问题:*/
#include<iostream>
using namespace std;
#include<cstdio>
#include<cstring>
int m,n,k;
int f[300][300];
struct G{
    int a,b,c;
};
G g[101];
int main()
{
    freopen("swim.in","r",stdin);
    freopen("swim.out","w",stdout);
    ios::sync_with_stdio(false);
    cin>>m>>n>>k;
    memset(f,99,sizeof(f));
    for(int i=1;i<=k;++i)
    cin>>g[i].a>>g[i].b>>g[i].c;
    f[0][0]=0;/*只把f[0][0]赋值为0,为了把背包恰好装满*/
    for(int i=1;i<=k;++i)
      for(int j=2*m;j>=g[i].a;--j)
        for(int l=2*n;l>=g[i].b;--l)
        f[j][l]=min(f[j][l],f[j-g[i].a][l-g[i].b]+g[i].c);
    int sum=999999;
    for(int i=m;i<=2*m;++i)/*因为氧气和氮气可以拿多了,所以从m到2吗,n到2n上寻找最小值*/
      for(int j=n;j<=2*n;++j)
      if(f[i][j]<sum)
      {
          sum=f[i][j];
      }
    cout<<sum<<endl;
    fclose(stdin);
    fclose(stdout);
    return 0;
}
View Code

8.庆功会

【问题描述】
w为了庆贺班级在校运动会上取得全校第一名成绩,班主任决定开一场庆功会,为此拨款购买奖品犒劳运动员。期望拨款金额能购买最大价值的奖品,可以补充他们的精力和体力。
【输入格式】
w第一行二个数n(n<=500),m(m<=6000),其中n代表希望购买的奖品的种数,m表示拨款金额。
w接下来n行,每行3个数,v、w、s,分别表示第I种奖品的价格、价值(价格与价值是不同的概念)和购买的数量(0件到s件均可),其中v<=100,w<=1000,s<=10。
【输出格式】
w第一行:一个数,表示此次购买能获得的最大的价值(注意!不是价格)。
【输入样例】
w5 1000
w80 20 4
w40 50 9
w30 50 7
w40 30 6
w20 20 1
【输出样例】
w1040
代码:
/*一个多重背包*/
#include<iostream>
#include<cstdio>
using namespace std;
int n,m,f[6001];
struct Wp{
    int v,w,s;
}; 
Wp wp[501];
int main()
{
    freopen("庆功会.in","r",stdin);
    freopen("庆功会.out","w",stdout);
    ios::sync_with_stdio(false);
    cin>>n>>m;
    for(int i=1;i<=n;++i)
    cin>>wp[i].v>>wp[i].w>>wp[i].s;
    for(int i=1;i<=n;++i)
      for(int j=m;j>0;--j)
        for(int k=0;k<=wp[i].s;++k)
        if(j>k*wp[i].v)
        f[j]=max(f[j],f[j-k*wp[i].v]+k*wp[i].w);
        else break;
    cout<<f[m]<<endl;
    fclose(stdin);
    fclose(stdout);
    return 0;
}
View Code

 9.暗黑破坏神

 

posted @ 2016-03-27 14:55  csgc0131123  阅读(567)  评论(0编辑  收藏  举报