分组背包——sicily 1750

1750. 运动会

限制条件

时间限制: 1 秒, 内存限制: 32 兆

题目描述

ZEH是一名04级的学生,他除了绩点高,还有运动细胞。有一次学院举办运动会,ZEH发现里面的 项目都是他所向披靡的,当然他想获得所有项目的No1,但是一个人的精力总是有限的,ZEH也是只有P(Power的简写,一个大于0且小于1000的整 数)的精力。如果精力足够参加比赛,一定能赢;相反,精力不够去参加比赛,Loss的概率很大,ZEH当然不想因为Loss而不爽。

整个运动会有N(大于0且小于等于100)项比赛,每项比赛都是在指定的一天D(D大于等于0)内举行完,但是一天可能同时有多个比赛同时进 行,ZEH当然就不能同时兼顾。比赛结束后,院长都会亲自为冠军颁发一定数额的奖金,其他名次只有一张奖状。ZEH当然是冲着奖金去的,他想获得最多的奖 金,师弟师妹们,你能帮ZEH大牛计算出他最多能拿多少奖金吗?

输入格式

第一行是一个整数T,表示这题有T个用例。
每个用例的第一行有两个正整数P N,分别表示ZEH的精力和比赛的项目。
第二行到第N+1行是N个项目,每一行有三个正整数D E M,分别表示这个项目在第D天举行,需要E的精力,和比赛的奖金。项目的顺序都按D排好序。

输出格式

对于每个用例,输出他能拿的最多的奖金。

样例输入

1
14 5
0 3 7
0 2 5
1 4 2
2 6 14
2 8 15

样例输出

23

刚开始的时候用一维dp[]去做,死活过不了,找了很久也没有找到原因,如果有哪位大神刚好看见,可以帮帮我查错。后来改用了二维的dp[][]做,顺利的AC。

这一题题目本身就有问题,提纲上说D是正整数,但是例子里面给的D第一个就为0,这个我们先不管,考虑题目本身。

题目本身就是一个典型的分组背包问题,首先,将给定的项目按天分组,用合适的数据结构存储起来。然后,按0-1背包的做法对天数进行选择,再在每天里对当天的项目做一个重复比较,最后一天只选到一个项目,原理和0-1背包是一致的。

核心代码:
 1 for(int i=0;i<=D;i++){
 2     if(xmP[i].size()==0)
 3         continue;
 4     for(int j=P;j>=1;j--){
 5         if (i>0)
 6             dp[i][j]=dp[i-1][j];
 7         for(int k=0;k<xmP[i].size();k++){
 8             if(xmP[i][k]<=j){
 9                 if(i>0)
10                     dp[i][j]=max(dp[i][j],dp[i-1][j-xmP[i][k]]+xmM[i][k]);
11                 else
12                     dp[i][j]=max(dp[i][j],dp[i][j-xmP[i][k]]+xmM[i][k]);
13             }
14         }
15         Max=max(Max,dp[i][j]);
16     }
17 }

对第0天的情况特殊处理了,还要注意dp[i][j]=max(dp[i][j],dp[i-1][j-xmP[i][k]]+xmM[i][k]);里的是dp[i][j]并不是dp[i-1][j]。

因为这里需要跟当天的上一个项目得出的结果做一个比较。

if (i>0)
 dp[i][j]=dp[i-1][j]; 已经进行了初始化,所以一开始进入k的循环dp[i][j]就是当天不选项目即dp[i-1][j]的情况。
附上全部代码:
#include<iostream>
#include<vector>
#include<algorithm>
#include<memory.h>

using namespace std;

int main()
{
    int T,P,N,D,E,M;
    int dp[101][1001];
    vector<int> xmP[101];
    vector<int> xmM[101];
    cin>>T;
    while(T--){
        cin>>P>>N;
        for(int i=0;i<101;i++){
            xmP[i].clear();
            xmM[i].clear();
        }
        for(int i=0;i<N;i++){
            cin>>D>>E>>M;
            xmP[D].push_back(E);
            xmM[D].push_back(M);
        }
        memset(dp,0,sizeof(dp));
        int Max=0;
        for(int i=0;i<=D;i++){
            if(xmP[i].size()==0)
                continue;
            for(int j=P;j>=1;j--){
                if (i>0)
                    dp[i][j]=dp[i-1][j];
                for(int k=0;k<xmP[i].size();k++){
                    if(xmP[i][k]<=j){
                        if(i>0)
                            dp[i][j]=max(dp[i][j],dp[i-1][j-xmP[i][k]]+xmM[i][k]);
                        else
                            dp[i][j]=max(dp[i][j],dp[i][j-xmP[i][k]]+xmM[i][k]);
                    }
                }
                Max=max(Max,dp[i][j]);
            }
        }
        cout<<Max<<endl;
    }
    return 0;
}                     
				
时间: 2024-08-16 20:41:38

分组背包——sicily 1750的相关文章

VijosP1250:分组背包

背景 Wind设计了很多机器人.但是它们都认为自己是最强的,于是,一场比赛开始了~ 描述 机器人们都想知道谁是最勇敢的,于是它们比赛搬运一些物品. 它们到了一个仓库,里面有n个物品,每个物品都有一个价值Pi和重量Wi,但是有些物品放在一起会爆炸,并且爆炸具有传递性.(a和b会爆炸.b和c会爆炸则a和c会爆炸)机器人们可不想因此损失自己好不容易从Wind那里敲诈来的装备,于是它们想知道在能力范围内,它们最多可以拿多少价值的物品. 你能帮助它们吗? 格式 输入格式 每组测试数据第1行为n,Wmax,

HDU-1011 Starship Troopers (树形DP+分组背包)

题目大意:给一棵有根带点权树,并且给出容量.求在不超过容量下的最大权值.前提是选完父节点才能选子节点. 题目分析:树上的分组背包. ps:特判m为0时的情况. 代码如下: # include<iostream> # include<cstdio> # include<vector> # include<cstring> # include<algorithm> using namespace std; const int N=105; const

HDU 4003 Find Metal Mineral (树形DP,树形分组背包,经典)

题意:给定一棵树图,n个节点,有边权,要派k<11个机器人从节点s出发,遍历所有的点,每当1只机器人经过1条边时就会花费该边的边权,边是可重复走的.问遍历完所有点的最小花费? 思路: 非常经典,首先需要知道一点,才能往下推理.就是“如果在t点派c个机器人往孩子u,那么最多只有1个机器人能走会回来到t,否则花费总是不划算的”. 稍微证明一下: (1)假设派1个机器人往u,逛一圈回到u的父亲t,花费v= 子树u的边权和*2 + e(t,u)*2.若机器人不要了,那花费肯定比v还要少. (2)假设派2

HDU 1712 ACboy needs your help-dp-(分组背包模型)

题意:n门课程用m天来学习,每门课用不同的天数来学习会有不同的学分,求能得到的最大的学分 分析:第一次接触分组背包.分组背包的模型就是不同的物品有不同的花费和价值,求在规定花费内能得到的最大的价值,这前面跟以前的背包最大的不同是物品分为几组,每组内的物品最多只能选一种:dp[i][j]表示前i组花费j能得到的最大的价值,不过实际在做的时候用一维数组就可以了 公式: for 组i for 花费j (从大到小) for 组内物品k if(j>=c[k]) dp[j]=max(dp[j],dp[j-c

hdu 1712 分组背包

背景:1Y,01背包多加了一个挑选循环而已. 分组背包的典型描述:对于很多背包,把它分为k个组,每个组内的组员是相互冲突的,所以只能选择一个. 我的代码: #include<cstdio> #include<iostream> #include<cstring> using namespace std; int main(void){ int n,m; while(scanf("%d%d",&n,&m),n*n+m*m){ int c

hdu4003 树形dp+分组背包

http://acm.hdu.edu.cn/showproblem.php?pid=4003 Problem Description Humans have discovered a kind of new metal mineral on Mars which are distributed in point‐like with paths connecting each of them which formed a tree. Now Humans launches k robots on

【HDU1712】ACboy needs your help(分组背包)

将背包九讲往后看了看,学习了一下分组背包.来做几道入门题,试试手. 1 #include <iostream> 2 #include <cstring> 3 #include <cstdlib> 4 #include <cstdio> 5 #include <cmath> 6 #include <cctype> 7 #include <algorithm> 8 #include <numeric> 9 #inc

洛谷——P1757 通天之分组背包

https://www.luogu.org/problem/show?pid=1757#sub 题目背景 直达通天路·小A历险记第二篇 题目描述 自01背包问世之后,小A对此深感兴趣.一天,小A去远游,却发现他的背包不同于01背包,他的物品大致可分为k组,每组中的物品相互冲突,现在,他想知道最大的利用价值是多少. 输入输出格式 输入格式: 两个数m,n,表示一共有n件物品,总重量为m 接下来n行,每行3个数ai,bi,ci,表示物品的重量,利用价值,所属组数 输出格式: 一个数,最大的利用价值

D. Arpa&#39;s weak amphitheater and Mehrdad&#39;s valuable Hoses 分组背包模板题

http://codeforces.com/problemset/problem/742/D 并查集预处理出所有关系. 一开始的时候,我预处理所有关系后,然后选择全部的时候,另起了一个for,然后再判断. 这样是不对的.因为这样使得同一组里面可能选择了两次. 3 0 2 1 2 3 1 1 3 #include <cstdio> #include <cstdlib> #include <cstring> #include <cmath> #include &