HDU4341-Gold miner-分组DP

模拟黄金矿工这个游戏,给出每一个金子的位置和所需时间,计算在给定时间内最大收益。

刚看这道题以为金子的位置没什么用,直接DP就行,WA了一发终于明白如果金子和人共线的话只能按顺序抓。

这就是需要考虑先后关系问题。看了背包⑨讲之后以为是“有依赖关系的背包”,感觉解决方案很不明显,想不出来做法。

后来想到,可以把共线的金子按1,1+2,1+2+3。。。变成若干个,然后共线的金子组成一组。

显然这个问题就变成了在组内互斥的情况下的分组DP,背包⑨讲已经给出了伪代码。

预处理的时候使用了优先队列,map,乱搞了一下就好了。。。//好不容易自己写出来了一道不太水的题。。。

 1 #include <cstdio>
 2 #include <algorithm>
 3 #include <cstring>
 4 #include <queue>
 5 #include <stack>
 6 #include <map>
 7
 8 using namespace std;
 9
10 const int maxn = 200+10;
11
12 struct node
13 {
14     int x,y;
15     int w,v;
16     node(){x=0;y=0;w=0;v=0;}
17     node(int x,int y) {w=x;v=y;}
18     bool operator < (const node &b) const
19     {
20         return x*x+y*y > b.x*x+b.y*y;
21     }
22
23 }gold[maxn];
24
25 struct item
26 {
27     int w,v;
28     item(){w=0;v=0;}
29     item(int a,int b){w=a;v=b;}
30 };
31
32 int x[maxn],y[maxn],w[maxn],v[maxn],dp[40010];
33 int N,T;
34 vector <item> itm[maxn];
35
36 int main()
37 {
38     int cas = 1;
39     while(~scanf("%d%d",&N,&T))
40     {
41         map<pair<int,int> , int > mp;
42         priority_queue<node> pq[maxn];
43         int cnt_group = 0;
44         for(int i=0;i<maxn;i++) itm[i].clear();
45
46         for(int i=0,x,y;i<N;i++)
47         {
48             scanf("%d%d%d%d",&gold[i].x,&gold[i].y,&gold[i].w,&gold[i].v);
49             x = gold[i].x;y = gold[i].y;
50
51             if(mp.count(pair<int,int>( x/__gcd(x,y) , y/__gcd(x,y)) ))
52             {
53                 pq[mp[pair<int,int>( x/__gcd(x,y) , y/__gcd(x,y))]].push(gold[i]);
54             }
55             else
56             {
57                 mp[pair<int,int>( x/__gcd(x,y) , y/__gcd(x,y))]=cnt_group++;
58                 pq[mp[pair<int,int>( x/__gcd(x,y) , y/__gcd(x,y))]].push(gold[i]);
59             }
60         }
61
62         map<pair<int,int>,int >::iterator it;
63         node cur;
64         for(int i=0;i<cnt_group;i++)
65         {
66             cur = node(0,0);
67             while(!pq[i].empty())
68             {
69                 cur.w += pq[i].top().w;
70                 cur.v += pq[i].top().v;
71                 pq[i].pop();
72                 itm[i].push_back(item(cur.w,cur.v));
73                 //printf("grp:%d w:%d v:%d\n",i,cur.w,cur.v);
74             }
75         }
76         memset(dp,0,sizeof dp);
77
78         for(int gp=0;gp<cnt_group;gp++)
79         {
80             int n = itm[gp].size();
81
82             for(int t=T;t>=0;t--)
83             {
84                 for(int i=0;i<n;i++) if(t>=itm[gp][i].w)
85                 {
86                     //printf("t:%d w:%d\n",t,itm[gp][i].w);
87                     dp[t] = max(dp[t],dp[t-itm[gp][i].w] + itm[gp][i].v);
88                 }
89             }
90         //for(int i=0;i<T;i++)
91             //printf("%d ",dp[i]);
92         //printf("\n");
93         }
94
95         printf("Case %d: %d\n",cas++,dp[T]);
96     }
97 }
时间: 2024-08-26 06:18:43

HDU4341-Gold miner-分组DP的相关文章

HDU 4341 Gold miner(分组背包)

http://acm.hdu.edu.cn/showproblem.php?pid=4341 题意: 一个人在原点(0,0)抓金子,每块金子是二维坐标平面的一个点(x,y)且y>0. 每块金子有一个价值v和获得需要的时间t.如果多个金子在一条从原点射出的直线上,那只能先抓近的,再抓远的.求在给定时间T下,所能获得的最大价值. 分析: 首先想想如果所有点都不共线是什么情况? 就是在给定时间T内要获取最大的价值和的点, 且所有点都可以任意选取. 那么这就是一个01背包问题. 不过如果存在共线的点,那

HDU 4341 Gold miner 分组背包变形

题意: 挖金矿,人在(0,0)点 n个金子 游戏时间为T 下面n行 (x, y) cost val 且若人 和 多块金子共线时,只能先取最近的金子,依次取,就是和游戏一样的. 且所有点只在1 2象限 思路: 我们先把所有共线的点分组 对于每组的物品,我们都可以认为取这个物品的花费就是前面所有物品的花费总和,而价值就是前面所有物品的价值总和. 这样就能消除每组物品的先取后取的影响了,但有一个情况就是这组至多只能取一个物品,所以每个状态只能是取了这个物品后或者是原始状态. 用原始状态转移,然后和原始

2012 #5 Gold miner

Gold miner Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 1889    Accepted Submission(s): 740Time Limit:2000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u Submit Status Practice 

!HDU 1024 Max Sum Plus Plus-dp-(分组dp?最大分段子序列和)

题意:n个数,分成m段,求这m段的最大和,段之间不能交叉. 分析: 这题跟最大子序列和的区别在于要求分成m段,所以做法就千差万别了.实际的做法倒有点像分组dp(将n个数分成m组),但是本题与上次写的两道分组dp(搬寝室和特殊的筷子)的不同是:上两题每组选两or三个元素,本题不确定每一段要选多少个元素:上两题先排序再做,这题只能根据序列原定顺序走. 本题难点: 1.状态:dp[i][j]在确定选第j个元素的前提下,前j个分i段的最大和:所有对于j号元素有两种情况:1).加入已经确定的i段中最后一段

01背包(分组) HDOJ 4341 Gold miner

题目传送门 题意:有n个金矿,每个金矿有抓取的消耗的时间和价值,矿工在原点,问在T时间内能得到的最大的价值 分析:唯一和01背包不同的是金矿可能共线,也就是抓取近的金矿后才能抓后面共线的金矿.这是分组背包问题,方法是将点按照斜率排序,如果相等按照距离原点远近排序,将斜率相等的点分成一组,每组的点累加上前面的点的时间和价值,这样每组只选一个点,就是01背包了 收获:分组背包问题 代码: /************************************************ * Auth

【HDOJ】4341 Gold miner

分组01背包.在一条直线上的点归为一组. 1 /* 4341 */ 2 #include <iostream> 3 #include <sstream> 4 #include <string> 5 #include <map> 6 #include <queue> 7 #include <set> 8 #include <stack> 9 #include <vector> 10 #include <de

BZOJ 1296: [SCOI2009]粉刷匠 分组DP

1296: [SCOI2009]粉刷匠 Description windy有 N 条木板需要被粉刷. 每条木板被分为 M 个格子. 每个格子要被刷成红色或蓝色. windy每次粉刷,只能选择一条木板上一段连续的格子,然后涂上一种颜色. 每个格子最多只能被粉刷一次. 如果windy只能粉刷 T 次,他最多能正确粉刷多少格子? 一个格子如果未被粉刷或者被粉刷错颜色,就算错误粉刷. Input 输入文件paint.in第一行包含三个整数,N M T. 接下来有N行,每行一个长度为M的字符串,'0'表示

HDU 4341 Gold miner

先把线按照距离原点的距离排序,然后用叉积把在同一条直线上的点放在一起, 把在同一条线上的点中的前i个点当成一个点就,就转化成了分组背包. 写if(kas++) putchar('\n') 居然PE了 #include<bits/stdc++.h> using namespace std; int N,T; const int maxn = 203; const int MAXT = 40005; struct Point { int x,y,t,v; }P[maxn]; bool vis[ma

HDU 1712 裸分组dp

http://acm.hdu.edu.cn/showproblem.php?pid=1712 N门课M天复习,第i门课花费j天获得的效益是dp[i][j] 求最大效益 分组背包,同一门课不能选两次 三层循环 第一层:几个分组循环 第二层:总容量递减 第三层:抉择构成背包 dp[j]=max(dp[j],dp[j-c[k]]+w[k]);(其中c[k]为k物品的费用,w[k]为价值),由于递降枚举背包容量,max比较中的dp[j]是由上一组物品决策所得,在这里将被忽略.就算不忽略,在本组物品中dp

LightOJ 1030 Discovering Gold (概率/期望DP)

题目链接:LightOJ - 1030 Description You are in a cave, a long cave! The cave can be represented by a \(1 \times N\) grid. Each cell of the cave can contain any amount of gold. Initially you are in position \(1\). Now each turn you throw a perfect \(6\) s