hdu 4341 Gold miner(分组01背包)

来源:互联网 发布:c4d软件下载 编辑:程序博客网 时间:2024/04/28 18:21

http://acm.hdu.edu.cn/showproblem.php?pid=4341


看到这个图好亲切,黄金矿工,很好玩的游戏。。。

题意:矿工起初在(0,0)位置,有n种金矿,给出每种金矿的坐标,花费时间和价值。在同一条线上的金矿必须先抓近的再抓远的,若近的不抓没办法抓远的。要求在T时间内获得的最大价值。


思路:01背包问题,但需要变形。 变形之处就是解决在同一条线上的金矿。 分组背包,把在同一条线上的金矿分为同一组。先按斜率排序,斜率相等按距离排序。例如1,2,3,4,5,五种金矿,根据斜率计算出1和2;3和4斜率分别相等,那么可分为(1,2)(3,4)(5)三组。在这里由于先抓近的再抓远的,对于(3,4)一组,把3物品的时间和价值加到4物品上作为4物品的时间和价值。这样就对应了分组背包每组最多取一件。 形成分组背包模型后直接套模板。

#include <stdio.h>#include <string.h>#include <algorithm>#include <vector>using namespace std;int n,T;struct node{int x,y;int t,v;bool operator < (const struct node &tmp)const{if(y*tmp.x == x*tmp.y)//斜率相等,按距离从小到大排序,不能按y/x排,因为x可能为0.return y < tmp.y;return y*tmp.x < x*tmp.y;}}point[210];vector <struct node> edge[210];//保存分组后的状态int cnt;int dp[40010];int solve(){memset(dp,0,sizeof(dp));for(int i = 0; i <= cnt; i++){for(int j = T; j >= edge[i][0].t; j--){for(int k = 0; k < (int)edge[i].size(); k++)dp[j] = max(dp[j], dp[j-edge[i][k].t]+edge[i][k].v);}}return dp[T];}int main(){int item = 1;while(~scanf("%d %d",&n,&T)){for(int i = 0; i < n; i++)scanf("%d %d %d %d",&point[i].x,&point[i].y,&point[i].t,&point[i].v);sort(point,point+n);for(int i = 0; i < n; i++)edge[i].clear();cnt = 0;edge[cnt].push_back(point[0]);for(int i = 1; i < n; i++)//n件物品分组{if(point[i].x*point[i-1].y == point[i].y*point[i-1].x)edge[cnt].push_back(point[i]);else edge[++cnt].push_back(point[i]);}for(int i = 0; i <= cnt; i++){//修改同一条线上的金矿的时间和价值for(int j = 1; j < (int)edge[i].size(); j++){edge[i][j].t += edge[i][j-1].t;edge[i][j].v += edge[i][j-1].v;}}printf("Case %d: %d\n",item++,solve());}return 0;}


0 0
原创粉丝点击