动态规划之01背包

来源:互联网 发布:ubuntu重启网络管理 编辑:程序博客网 时间:2024/05/18 16:38

#1038 : 01背包

时间限制:20000ms
单点时限:1000ms
内存限制:256MB

描述

且说上一周的故事里,小Hi和小Ho费劲心思终于拿到了茫茫多的奖券!而现在,终于到了小Ho领取奖励的时刻了!

小Ho现在手上有M张奖券,而奖品区有N件奖品,分别标号为1到N,其中第i件奖品需要need(i)张奖券进行兑换,同时也只能兑换一次,为了使得辛苦得到的奖券不白白浪费,小Ho给每件奖品都评了分,其中第i件奖品的评分值为value(i),表示他对这件奖品的喜好值。现在他想知道,凭借他手上的这些奖券,可以换到哪些奖品,使得这些奖品的喜好值之和能够最大。

提示一:合理抽象问题、定义状态是动态规划最关键的一步

提示二:说过了减少时间消耗,我们再来看看如何减少空间消耗

输入

每个测试点(输入文件)有且仅有一组测试数据。

每组测试数据的第一行为两个正整数N和M,表示奖品的个数,以及小Ho手中的奖券数。

接下来的n行描述每一行描述一个奖品,其中第i行为两个整数need(i)和value(i),意义如前文所述。

测试数据保证

对于100%的数据,N的值不超过500,M的值不超过10^5

对于100%的数据,need(i)不超过2*10^5, value(i)不超过10^3

输出

对于每组测试数据,输出一个整数Ans,表示小Ho可以获得的总喜好值。

样例输入
5 1000144 990487 436210 673567 581056 897
样例输出
2099

题意:  经典的01背包问题, need[i]可以看成重量, value就是价值. 奖券数就是背包的容量.

分析: 用了两种方法来解决这道题,复杂度差别很大.


比较慢的方法:

#include<bitset> //900ms#include<map>#include<vector>#include<cstdio>#include<iostream>#include<cstring>#include<string>#include<algorithm>#include<cmath>#include<stack>#include<queue>#include<set>#define inf 0x3f3f3f3f#define mem(a,x) memset(a,x,sizeof(a))using namespace std;typedef long long ll;typedef pair<int,int> pii;inline int in(){    int res=0;char c;int f=1;    while((c=getchar())<'0' || c>'9')if(c=='-')f=-1;    while(c>='0' && c<='9')res=res*10+c-'0',c=getchar();    return res*f;}const int N=100010;int dp[N*5],v[5555],w[555];  //dp[i]表示 价值和 为i的时候最小的重量是多少int main(){    int n=in(),m=in(),sum=0;    for(int i=0;i<n;i++)    {        w[i]=in(),v[i]=in();        sum += v[i];    }    mem(dp,inf);       //初始化为无穷大    dp[0]=0;    for(int i=0;i<n;i++)    {        for(int j=sum;j>=v[i];j--)  //从sum开始逆向循环,保证每个物品只能被用一次        {            dp[j]=min(dp[j],dp[j-v[i]]+w[i]);        }    }    for(int i=sum;i>=0;i--)    {        if(dp[i]<=m)        {            printf("%d\n",i);            break;        }    }    return 0;}

比较经典的方法:

由于hihocoder是单组数据, 不用每次给数组赋值0. 多组数据的时候要记得归零

#include<bitset> //195ms#include<map>#include<vector>#include<cstdio>#include<iostream>#include<cstring>#include<string>#include<algorithm>#include<cmath>#include<stack>#include<queue>#include<set>#define inf 0x3f3f3f3f#define mem(a,x) memset(a,x,sizeof(a))using namespace std;typedef long long ll;typedef pair<int,int> pii;inline int in(){    int res=0;char c;int f=1;    while((c=getchar())<'0' || c>'9')if(c=='-')f=-1;    while(c>='0' && c<='9')res=res*10+c-'0',c=getchar();    return res*f;}const int N=100010;int dp[N],w[555],v[555]; //重量为i的时候最大的价值是多少int main(){    int n=in(),m=in();    for(int i=0;i<n;i++)    {        w[i]=in(),v[i]=in();    }    for(int i=0;i<n;i++)    {        for(int j=m;j>=w[i];j--)   //从m开始逆向循环,保证每个物品只能用一次        {            dp[j]=max(dp[j],dp[j-w[i]]+v[i]);        }    }    printf("%d\n",dp[m]);    return 0;}



第一种方法在这里显然是慢了很多的,但是要是w[i]与背包容量的值变得很大, 而value值变得很小, 就体现出它的优势了.比如下面这题


Problem 2214 Knapsack problem

Accept: 15    Submit: 32
Time Limit: 3000 mSec    Memory Limit : 32768 KB

Problem Description

Given a set of n items, each with a weight w[i] and a value v[i], determine a way to choose the items into a knapsack so that the total weight is less than or equal to a given limit B and the total value is as large as possible. Find the maximum total value. (Note that each item can be only chosen once).

Input

The first line contains the integer T indicating to the number of test cases.

For each test case, the first line contains the integers n and B.

Following n lines provide the information of each item.

The i-th line contains the weight w[i] and the value v[i] of the i-th item respectively.

1 <= number of test cases <= 100

1 <= n <= 500

1 <= B, w[i] <= 1000000000

1 <= v[1]+v[2]+...+v[n] <= 5000

All the inputs are integers.

Output

For each test case, output the maximum value.

Sample Input

15 1512 42 21 14 101 2

Sample Output

15

题意: 依然是01背包,,,

分析:数据变了, 换一种想法就行了.


#include<bitset> //1000+ms#include<map>#include<vector>#include<cstdio>#include<iostream>#include<cstring>#include<string>#include<algorithm>#include<cmath>#include<stack>#include<queue>#include<set>#define inf 0x3f3f3f3f#define mem(a,x) memset(a,x,sizeof(a))using namespace std;typedef long long ll;typedef pair<int,int> pii;inline int in(){    int res=0;char c;    while((c=getchar())<'0' || c>'9');    while(c>='0' && c<='9')res=res*10+c-'0',c=getchar();    return res;}const int N=100010;int dp[5001],w[505],v[505]; //dp表示 价值和 为i 的时候重量的最小值int main(){    int T=in();    while(T--)    {        int n=in(),m=in();        int sum=0;        for(int i=0;i<n;i++)        {            w[i]=in(),v[i]=in();            sum += v[i];        }        mem(dp,inf);       //初始化为无穷大        dp[0]=0;        for(int i=0;i<n;i++)        {            for(int j=sum;j>=v[i];j--)               {                dp[j]=min(dp[j],dp[j-v[i]]+w[i]);            }        }        for(int i=sum;i>=0;i--)        {            if(dp[i]<=m)            {                printf("%d\n",i);                break;            }        }    }    return 0;}




0 0
原创粉丝点击