hdu 3496 Watch The Movie 二维费用背包

来源:互联网 发布:js 将图片转为base64 编辑:程序博客网 时间:2024/05/16 18:07

Description

New semester is coming, and DuoDuo has to go to school tomorrow. She decides to have fun tonight and will be very busy after tonight. She like watch cartoon very much. So she wants her uncle to buy some movies and watch with her tonight. Her grandfather gave them L minutes to watch the cartoon. After that they have to go to sleep. 
DuoDuo list N piece of movies from 1 to N. All of them are her favorite, and she wants her uncle buy for her. She give a value Vi (Vi > 0) of the N piece of movies. The higher value a movie gets shows that DuoDuo likes it more. Each movie has a time Ti to play over. If a movie DuoDuo choice to watch she won’t stop until it goes to end. 
But there is a strange problem, the shop just sell M piece of movies (not less or more then), It is difficult for her uncle to make the decision. How to select M piece of movies from N piece of DVDs that DuoDuo want to get the highest value and the time they cost not more then L. 
How clever you are! Please help DuoDuo’s uncle. 
 

Input

The first line of the input file contains a single integer t (1 ≤ t ≤ 10), the number of test cases, followed by input data for each test case: 
The first line is: N(N <= 100),M(M<=N),L(L <= 1000) 
N: the number of DVD that DuoDuo want buy. 
M: the number of DVD that the shop can sale. 
L: the longest time that her grandfather allowed to watch. 
The second line to N+1 line, each line contain two numbers. The first number is the time of the ith DVD, and the second number is the value of ith DVD that DuoDuo rated. 
 

Output

Contain one number. (It is less then 2^31.) 
The total value that DuoDuo can get tonight. 
If DuoDuo can’t watch all of the movies that her uncle had bought for her, please output 0. 
 

Sample Input

13 2 1011 1001 29 1
 

Sample Output

3
 先解释一下二位费用背包:
二维费用的背包问题
问题
二维费用的背包问题是指:对于每件物品,具有两种不同的费用;选择这件物品必须同时付出这两种代价;对于每种代价都有 一个可付出的最大值(背包容量)。问怎样选择物品可以得到最大的价值。设这两种代价分别为代价1和代价2,第i件物品所需的两种代价分别为a[i]和 b[i]。两种代价可付出的最大值(两种背包容量)分别为V和U。物品的价值为w[i]。

算法
费用加了一维,只需状态也加一维即可。设f[i][v][u]表示前i件物品付出两种代价分别为v和u时可获得的最大价值。状态转移方程就是:

f[i][v][u]=max{f[i-1][v][u],f[i-1][v-a[i]][u-b[i]]+w[i]}

如前述方法,可以只使用二维的数组:当每件物品只可以取一次时变量v和u采用逆序的循环,当物品有如完全背包问题时采用顺序的循环。当物品有如多重背包问题时拆分物品。这里就不再给出伪代码了,相信有了前面的基础,你能够自己实现出这个问题的程序。

物品总个数的限制
有时,“二维费用”的条件是以这样一种隐含的方式给出的:最多只能取M件物品。这事实上相当于每件物品多了一种“件数 ”的费用,每个物品的件数费用均为1,可以付出的最大件数费用为M。换句话说,设f[v][m]表示付出费用v、最多选m件时可得到的最大价值,则根据物 品的类型(01、完全、多重)用不同的方法循环更新,最后在f[0..V][0..M]范围内寻找答案。

复数域上的背包问题
另一种看待二维背包问题的思路是:将它看待成复数域上的背包问题。也就是说,背包的容量以及每件物品的费用都是一个复 数。而常见的一维背包问题则是实数域上的背包问题。(注意:上面的话其实不严谨,因为事实上我们处理的都只是整数而已。)所以说,一维背包的种种思想方法,往往可以应用于二位背包问题的求解中,因为只是数域扩大了而已。

作为这种思想的练习,你可以尝试将P11中提到的“子集和问题”扩展到复数域(即二维),并试图用同样的复杂度解决。

小结
当发现由熟悉的动态规划题目变形得来的题目时,在原来的状态中加一纬以满足新的限制是一种比较通用的方法。希望你能从本讲中初步体会到这种方法。

题意:
给你n张电影门票,但一次只可以买m张,并且你最多可以看L分钟,接下来是n场电影,每一场电影a分钟,b价值,要求恰好看m场电影所得到的最大价值,要是看不到m场电影,输出0;

这道题目看起来挺简单就是一道简单的二维费用背包,但是我却做了一下午,唉,弱爆了,主要纠结初始化问题。。
#include<cstdio>#include<iostream>#include<algorithm>#include<cstring>#define INF 0x3f3f3f3fusing namespace std;int dp[105][1105];int main(){    int t;    int w[105],p[105];    scanf("%d",&t);    while(t--)    {        int n,m,l;        scanf("%d %d %d",&n,&m,&l);        for(int i=1; i<=n; i++)        {            scanf("%d %d",&w[i],&p[i]);        }        memset(dp,-1,sizeof(dp));        for(int i=0; i<=l; i++)            dp[0][i]=0;        for(int i=1; i<=n; i++)        {            for(int k=m; k>=1; k--)            {                for(int j=l; j>=w[i]; j--)                {                    if(dp[k-1][j-w[i]]!=-1)                        dp[k][j]=max(dp[k][j],dp[k-1][j-w[i]]+p[i]);                }            }        }        dp[m][l]=max(0,dp[m][l]);        printf("%d\n",dp[m][l]);    }    return 0;}

#include<cstdio>#include<iostream>#include<algorithm>#include<cstring>#define INF 0x3f3f3f3fusing namespace std;int dp[105][1105];int main(){    int t;    int w[105],p[105];    scanf("%d",&t);    while(t--)    {        int n,m,l;        scanf("%d %d %d",&n,&m,&l);        for(int i=1; i<=n; i++)        {            scanf("%d %d",&w[i],&p[i]);        }        memset(dp,-INF,sizeof(dp));        memset(dp[0],0,sizeof(dp[0]));        for(int i=1; i<=n; i++)        {            for(int k=m; k>=1; k--)            {                for(int j=l; j>=w[i]; j--)                {                   // if(dp[k-1][j-w[i]]!=-1)                        dp[k][j]=max(dp[k][j],dp[k-1][j-w[i]]+p[i]);                }            }        }        dp[m][l]=max(0,dp[m][l]);        printf("%d\n",dp[m][l]);    }    return 0;}


0 0
原创粉丝点击