背包入门

A - Bone Collector HDU - 2602

题意:给定背包的最大体积和物品的数量,每一个物品的价值和体积,01背包板子

题解:01背包

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<sstream>
#include<cmath>
#include<stack>
#include<cstdlib>
#include <vector>
#include<queue>
using namespace std;

#define ll long long
#define llu unsigned long long
#define INF 0x3f3f3f3f
#define PI acos(-1.0)
const int maxn =  1e5+5;
const int  mod = 1e9+7;

ll value[maxn];
ll weight[maxn];
ll dp[maxn];

void init()
{
    memset(value,0,sizeof value);
    memset(weight,0,sizeof weight);
    memset(dp,0,sizeof dp);
}
int main()
{

    int t;
    scanf("%d",&t);
    while(t--)
    {
        init();
        ll N,V;
        scanf("%lld %lld",&N,&V);
        for(int i = 1; i <= N; i++)
            scanf("%lld",&value[i]);
        for(int i = 1; i <= N; i++)
            scanf("%lld",&weight[i]);
        for(int i = 1; i <= N; i++)
            for (int j = V; j >= weight[i]; j--)
                dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);
        printf("%lld\n",dp[V]);

    }
}
View Code

B - 饭卡 HDU - 2546 

电子科大本部食堂的饭卡有一种很诡异的设计,即在购买之前判断余额。如果购买一个商品之前,卡上的剩余金额大于或等于5元,就一定可以购买成功(即使购买后卡上余额为负),否则无法购买(即使金额足够)。所以大家都希望尽量使卡上的余额最少。 
某天,食堂中有n种菜出售,每种菜可购买一次。已知每种菜的价格以及卡上的余额,问最少可使卡上的余额为多少。 

Input多组数据。对于每组数据: 
第一行为正整数n,表示菜的数量。n<=1000。 
第二行包括n个正整数,表示每种菜的价格。价格不超过50。 
第三行包括一个正整数m,表示卡上的余额。m<=1000。 

n=0表示数据结束。 
Output对于每组输入,输出一行,包含一个整数,表示卡上可能的最小余额。Sample Input

1
50
5
10
1 2 3 2 1 1 2 3 2 1
50
0

Sample Output

-45
32

思路:动态规划,最后一次肯定是买最贵的那个菜,之前就余额大于等于5的前提下,能买多少就买多少

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<sstream>
#include<cmath>
#include<stack>
#include<cstdlib>
#include <vector>
#include<queue>
using namespace std;

#define ll long long
#define llu unsigned long long
#define INF 0x3f3f3f3f
#define PI acos(-1.0)
const int maxn =  1e5+5;
const int  mod = 1e9+7;

ll value[maxn];
ll weight[maxn];
ll dp[maxn];

void init()
{
    memset(value,0,sizeof value);
    memset(weight,0,sizeof weight);
    memset(dp,0,sizeof dp);
}
int main()
{


    while(true)
    {
        init();
        ll N,V;
        scanf("%lld",&N);
        if(N == 0)
            break;
//        for(int i = 1; i <= N; i++)
//            scanf("%lld",&value[i]);
        ll maxx = -1;
        ll pos;
        for(int i = 1; i <= N; i++)
        {
            scanf("%lld", &weight[i]);
            if(maxx < weight[i])
            {
                maxx = weight[i];
                pos = i;
            }
        }
       scanf("%lld",&V);
        if(V < 5) {
           
            printf("%lld\n", V);
            continue;
        }
        for(int i = 1; i <= N; i++) {
            if(i == pos)
                continue;
            for (int j = V; j >= weight[i]; j--) {
                dp[j] = max(dp[j], dp[j - weight[i]] + weight[i]);
            }
        }
        printf("%lld\n",V - dp[V-5] - maxx);

    }
}
View Code

C - 湫湫系列故事——减肥记I HDU - 4508

 对于吃货来说,过年最幸福的事就是吃了,没有之一! 
  但是对于女生来说,卡路里(热量)是天敌啊! 
  资深美女湫湫深谙“胖来如山倒,胖去如抽丝”的道理,所以她希望你能帮忙制定一个食谱,能使她吃得开心的同时,不会制造太多的天敌。 

  当然,为了方便你制作食谱,湫湫给了你每日食物清单,上面描述了当天她想吃的每种食物能带给她的幸福程度,以及会增加的卡路里量。 

Input  输入包含多组测试用例。 
  每组数据以一个整数n开始,表示每天的食物清单有n种食物。 
  接下来n行,每行两个整数a和b,其中a表示这种食物可以带给湫湫的幸福值(数值越大,越幸福),b表示湫湫吃这种食物会吸收的卡路里量。 
  最后是一个整数m,表示湫湫一天吸收的卡路里不能超过m。 

   [Technical Specification] 
  1. 1 <= n <= 100 
  2. 0 <= a,b <= 100000 
  3. 1 <= m <= 100000 
Output  对每份清单,输出一个整数,即满足卡路里吸收量的同时,湫湫可获得的最大幸福值。Sample Input

3
3 3
7 7
9 9
10
5
1 1
5 3
10 3
6 8
7 5
6

Sample Output

10
20

题解:完全背包

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<sstream>
#include<cmath>
#include<stack>
#include<cstdlib>
#include <vector>
#include<queue>
using namespace std;

#define ll long long
#define llu unsigned long long
#define INF 0x3f3f3f3f
#define PI acos(-1.0)
const int maxn =  1e5+5;
const int  mod = 1e9+7;

ll value[maxn];
ll weight[maxn];
ll dp[maxn];

void init()
{
    memset(value,0,sizeof value);
    memset(weight,0,sizeof weight);
    memset(dp,0,sizeof dp);
}
int main()
{
        ll N,V;
        while(~scanf("%lld",&N)) {
            init();
            for (int i = 1; i <= N; i++) {
                scanf("%lld %lld", &value[i], &weight[i]);
            }
            scanf("%lld", &V);
            for (int i = 1; i <= N; i++)
                for (int j = weight[i]; j <= V; j++)
                    dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);
            printf("%lld\n", dp[V]);
        }

}
View Code

D - 寒冰王座 HDU - 1248

不死族的巫妖王发工资拉,死亡骑士拿到一张N元的钞票(记住,只有一张钞票),为了防止自己在战斗中频繁的死掉,他决定给自己买一些道具,于是他来到了地精商店前. 

死亡骑士:"我要买道具!" 

地精商人:"我们这里有三种道具,血瓶150块一个,魔法药200块一个,无敌药水350块一个." 

死亡骑士:"好的,给我一个血瓶." 

说完他掏出那张N元的大钞递给地精商人. 

地精商人:"我忘了提醒你了,我们这里没有找客人钱的习惯的,多的钱我们都当小费收了的,嘿嘿." 

死亡骑士:"......" 

死亡骑士想,与其把钱当小费送个他还不如自己多买一点道具,反正以后都要买的,早点买了放在家里也好,但是要尽量少让他赚小费. 

现在死亡骑士希望你能帮他计算一下,最少他要给地精商人多少小费. 

Input输入数据的第一行是一个整数T(1<=T<=100),代表测试数据的数量.然后是T行测试数据,每个测试数据只包含一个正整数N(1<=N<=10000),N代表死亡骑士手中钞票的面值. 

注意:地精商店只有题中描述的三种道具.

题解:物品的value和weight已知

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<sstream>
#include<cmath>
#include<stack>
#include<cstdlib>
#include <vector>
#include<queue>
using namespace std;

#define ll long long
#define llu unsigned long long
#define INF 0x3f3f3f3f
#define PI acos(-1.0)
const int maxn =  1e5+5;
const int  mod = 1e9+7;

ll value[maxn]={150,200,350};
ll weight[maxn]={150,200,350};
ll dp[maxn];

void init()
{
//    memset(value,0,sizeof value);
//    memset(weight,0,sizeof weight);
    memset(dp,0,sizeof dp);
}
int main()
{
        ll N,V;
        int t;
        scanf("%d",&t);
        while(t--)
        {
            //scanf("%lld",&N);
            init();
//            for (int i = 1; i <= N; i++) {
//                scanf("%lld %lld", &value[i], &weight[i]);
//            }
            scanf("%lld", &V);
            for (int i = 0; i <= 2; i++)
                for (int j = weight[i]; j <= V; j++)
                    dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);
            printf("%lld\n", V - dp[V]);
        }

}
View Code

E - Course Selection System ZOJ - 3956

题意:有 n 门课程,每门课程都有它的快乐值 Hi,学分 Ci。现在选择若干门课程(可不选),它们的舒适值的结果满足下式:

求舒适值最大是多少

题解:难点在于题目的理解,理解题目的意思并找到题目的每门课的value是H,weight是C

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<sstream>
#include<cmath>
#include<stack>
#include<cstdlib>
#include <vector>
#include<queue>
using namespace std;

#define ll long long
#define llu unsigned long long
#define INF 0x3f3f3f3f
#define PI acos(-1.0)
const int maxn =  1e5+5;
const int  mod = 1e9+7;

ll value[maxn];
ll weight[maxn];
ll dp[maxn];

ll calculate(ll C ,ll H)
{
    return H*H - H*C -C*C;
}
void init()
{
    memset(value,0,sizeof value);
    memset(weight,0,sizeof weight);
    memset(dp,0,sizeof dp);
}
int main()
{

    int t;
    scanf("%d",&t);
    while(t--)
    {
        init();
        ll N,V = 0;
        ll ans = 0;
        scanf("%lld",&N);
        for(int i = 1; i <= N; i++) {
            scanf("%lld %lld", &value[i], &weight[i]);
            V += weight[i];
        }

        for(int i = 1; i <= N; i++)
            for (int j = V; j >= weight[i]; j--)
                dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);

        for(int i = 0;i <= V;i++)
            ans = max(ans,calculate(i,dp[i]));
        printf("%lld\n",ans);

    }
}
View Code

F - 悼念512汶川大地震遇难同胞——珍惜现在,感恩生活 HDU - 2191

中文题题意跳过了

思路:多重背包问题。可以转换成为01背包解。多重背包转化为01背包的关键在于把件数从整体中孤立出来作为一个新的个体,也就是说不管分类,有多少件就有多少种

01做法:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<sstream>
#include<cmath>
#include<stack>
#include<cstdlib>
#include <vector>
#include<queue>
using namespace std;

#define ll long long
#define llu unsigned long long
#define INF 0x3f3f3f3f
#define PI acos(-1.0)
const int maxn =  1e5+5;
const int  mod = 1e9+7;

ll value[maxn];
ll weight[maxn];
ll dp[maxn];

void init()
{
    memset(value,0,sizeof value);
    memset(weight,0,sizeof weight);
    memset(dp,0,sizeof dp);
}
int main()
{

    int t;
    scanf("%d",&t);
    while(t--)
    {
        init();
        ll V,m;
        scanf("%lld %lld",&V,&m);
        int N = 1;
       for(int i=1;i<=m;i++)
       {
           int a,b,c;
           scanf("%d%d%d",&a,&b,&c);
           for(int j=1;j<=c;j++)
           {
               weight[N] = a;
               value[N] = b;
               N++;
           }
       }
        for(int i = 1; i <=N; i++)
            for (int j = V; j >= weight[i]; j--)
                dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);
        printf("%lld\n",dp[V]);

    }
}
View Code

多重做法:

#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
const int maxn=500;
int n,m,w[maxn],c[maxn],num[maxn],dp[maxn];
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
    int cur=0;
    scanf("%d%d",&n,&m);
    for(int i=0;i<m;i++)
        scanf("%d%d%d",&w[i],&c[i],&num[i]);
    int ans=0;
    memset(dp,0,sizeof(dp));
    for(int i=0;i<m;i++)
    {
        for(int j=n;j>=w[i];j--)
        {
        for(int k=1;k<=num[i];k++)
            if(j>=k*w[i])
            dp[j]=max(dp[j],dp[j-k*w[i]]+c[i]*k);
        ans=max(ans,dp[j]);
        }
    }
    printf("%d\n",ans);    
    }
    return 0;
}
View Code

G - ACboy needs your help HDU - 1712

题意:题意是有N天要学M门课,A[i][j]表示第i门课要上j天才可以获得的价值,每天最多只能上一门课,求N天可以获得的最大价值。

题解:难点在于题意,题意明白之后可知输入的是value[i][j],其中i是第i门课,j是需要花费j天,value[i][j]是第i门课话费j天可以获得的价值,每一门课不可以重复学习只能选择花费某天就可以理解为这一组里面只能选一个

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<sstream>
#include<cmath>
#include<stack>
#include<cstdlib>
#include <vector>
#include<queue>
using namespace std;

#define ll long long
#define llu unsigned long long
#define INF 0x3f3f3f3f
#define PI acos(-1.0)
const int maxn =  1e2+5;
const int  mod = 1e9+7;

ll value[maxn][maxn];
ll weight[maxn];
ll dp[maxn];
ll a[maxn][maxn];

void init()
{
    memset(value,0,sizeof value);
    memset(weight,0,sizeof weight);
    memset(dp,0,sizeof dp);
}
int main()
{

//    int t;
//    scanf("%d",&t);


    ll n;
    ll N,V;
    while(~scanf("%lld %lld",&n,&V) && n+V)
    {
        init();

        for(int i=1;i<=n;i++) {
            for (int j = 1; j <= V; j++) {
                scanf("%d", &value[i][j]);
            }
        }
        for(int i = 1; i <= n; i++)     //第一个循环枚举第几组(这里是第几个课程)
            for (int j = V; j >= 0; j--)    //第二个循环枚举背包的容量
                for(int k = 1; k <= j; k++)     //第三个循环枚举该组里的物品(这里是第i门课花费的1~j天)
                    dp[j] = max(dp[j], dp[j - k] + value[i][k]);
        printf("%lld\n",dp[V]);

    }
}
View Code

猜你喜欢

转载自www.cnblogs.com/smallhester/p/10296395.html