您的位置:首页 > 其它

[HDU 3535] AreYouBusy 混合背包

2015-07-28 09:35 573 查看
http://acm.hdu.edu.cn/showproblem.php?pid=3535

题意:输入两个数 n, T 表示有 n 类工作和 T 个单位的时间,然后输入 n 类工作,每一类先输入两个数 m,s 表示这类工作包含 m 个工作, 如果 s == 0 表示这类工作里面至少选一个去做, s == 1 表示这类工作里面做多只能做一个, s == 2 表示这类工作你随便选几个, 然后输入 m 行的两个数表示工作需要的时间和能得到的价值。

思路:

第一类:至少选一项,对于这一组的dp的初值,应该全部赋为负无穷,这样才能保证不会出现都不选的情况。

状态转移方程为 dp[i][k] = max{ dp[i][k], dp[i-1][k-vol] +v al, dp[i][k-vol]+val }。

dp[i][k]是不选择当前工作;

dp[i-1][k-vol]+val是选择当前工作,但是是第一次在本组中选;

dp[i][k-cost[j]]+val[j]表示选择当前工作,并且不是第一次取。

第二类:最多选一项,

状态转移方程为dp[i][k]=max{ dp[i][k], dp[i-1][k-vol]+val}。

由于要保证得到全局最优解,所以在该组DP开始以前,应该将上一组的DP结果先复制到这一组的dp[i]数组里,因为这一组的数据是在上一组数据的基础上进行更新的。

第三类:任意选,

状态转移方程为dp[i][k]=max{ dp[i][k],dp[i-1][k-vol]+val,dp[i][k-vol]+val}。

同样要保证为得到全局最优解,先复制上一组解。

[code]#include <cstdio>
#include <cstring>
#include <iostream>

using namespace std;

const int inf = (1<<31)-1;

int dp[105][105];

int main()
{
    int n, volume;
    while(cin>>n>>volume){
        int m, s, val, vol;
        memset(dp, 0, sizeof(dp));
        for(int i = 1; i <= n; i++){
            cin>>m>>s;
            if(s == 0){
                for(int k = 0; k <= volume; k++){
                    dp[i][k] = -inf;
                }
                while(m--){
                    cin>>vol>>val;
                    for(int k = volume; k >= vol; k--){
                        dp[i][k] = max(dp[i][k], dp[i][k-vol] + val);//不是第一次选
                        dp[i][k] = max(dp[i][k], dp[i-1][k-vol] + val);//第一次选必须由上一层传递
                    }
                }
            }
            else if(s == 1){
                for(int k = 0; k <= volume; k++){
                    dp[i][k] = dp[i-1][k];
                }
                while(m--){
                    cin>>vol>>val;
                    for(int k = volume; k >= vol; k--){
                        dp[i][k] = max(dp[i][k], dp[i-1][k-vol] + val); //必须由上一次传递,保证之选一个
                    }
                }
            }
            else{
                for(int k = 0; k <= volume; k++){
                    dp[i][k] = dp[i-1][k];
                }
                while(m--){
                    cin>>vol>>val;
                    for(int k = volume; k >= vol; k--){
                        dp[i][k] = max(dp[i][k], dp[i][k-vol] + val); //01背包
                        dp[i][k] = max(dp[i][k], dp[i-1][k-vol] + val);
                    }
                }
            }
        }
        cout<<max(-1, dp
[volume])<<endl;
    }
    return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: