HDU 4341 Gold miner(分组背包)

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

题意:

一个人在原点(0,0)抓金子,每块金子是二维坐标平面的一个点(x,y)且y>0. 每块金子有一个价值v和获得需要的时间t。如果多个金子在一条从原点射出的直线上,那只能先抓近的,再抓远的。求在给定时间T下,所能获得的最大价值。

分析:

首先想想如果所有点都不共线是什么情况? 就是在给定时间T内要获取最大的价值和的点, 且所有点都可以任意选取. 那么这就是一个01背包问题. 不过如果存在共线的点,那么如何处理呢?

我们把所有共(从原点射出的)直线的点分成1组, 然后每个组内只能选1个点. 比如如果你选了该组第i远的点, 那么你就必须把第1个第2个..第i-1 和第i个点都选了. 所以每组i点的花费和价值都是前面所有点的累加和.

现在的问题就变成了分组背包问题了: 对于每个给定的组, 组内最多只能选1个物品, 问你能获得的最大价值和.

我们令dp[i][j]==x表示只选前i组的物品,总花费<=j时能获得的最大价值==x.

初始化: dp全为0.

状态转移: dp[i][j] = max( dp[i-1][j] , dp[i-1][j-cost[k]]+val[k]) 其中cost[k]和val[k]是第i组物品中的第k个物品的花费和价值.

最终所求: dp[n][T].

注意程序实现的3层循环不能互换顺序, 因为要保证滚动数组的情况下, 实现上述的状态转移方程.

AC代码:

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
using namespace std;
const int maxn=200+5;

struct Point
{
    int x,y;
    int cost,val;
    bool operator<(const Point &rhs)const//极角排序
    {
        return x*rhs.y-y*rhs.x<0 || (x*rhs.y-y*rhs.x==0 && y<rhs.y);
    }
    bool operator==(const Point &rhs)const//共线判断
    {
        return x*rhs.y-y*rhs.x==0;
    }
}p[maxn];

int N,T;
int n;        //多少组
int num[maxn];//num[i]表示第i组的物品数
int cost[maxn][maxn];//cost[i][j]==x表示第i组第j个物品的花费
int val[maxn][maxn]; //cost[i][j]==x表示第i组第j个物品的价值
int dp[40000+5];

int main()
{
    int n,kase=0;
    while(scanf("%d%d",&N,&T)==2)
    {
        //读取输入
        for(int i=0;i<N;i++)
            scanf("%d%d%d%d",&p[i].x,&p[i].y,&p[i].cost,&p[i].val);
        sort(p,p+N);

        //原始物品分成n组,每组只取1个
        n=1;
        num[n]=1;
        cost[n][num[n]]=p[0].cost;
        val[n][num[n]]=p[0].val;
        for(int i=1;i<N;i++)
        {
            if(p[i]==p[i-1])//共线
            {
                num[n]++;
                cost[n][num[n]]=cost[n][num[n]-1]+p[i].cost;
                val[n][num[n]]=val[n][num[n]-1]+p[i].val;
            }
            else//不共线
            {
                n++;
                num[n]=1;
                cost[n][num[n]]=p[i].cost;
                val[n][num[n]]=p[i].val;
            }
        }

        //分组背包过程
        memset(dp,0,sizeof(dp));
        for(int i=1;i<=n;i++)
        for(int j=T;j>=0;j--)
        for(int k=1;k<=num[i];k++)
            if(j>=cost[i][k])
            dp[j] = max(dp[j], dp[j-cost[i][k]]+val[i][k]);

        printf("Case %d: %d\n",++kase,dp[T]);
    }
    return 0;
}
时间: 2024-10-13 03:14:38

HDU 4341 Gold miner(分组背包)的相关文章

HDU 4341 Gold miner 分组背包变形

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

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 1561 树形dp+分组背包

题意:就是给定n个点,每个地点有value[i]的宝物,而且有的宝物必须是另一个宝物取了才能取,问取m个点可以获得的最多宝物价值. 一个子节点就可以返回m个状态,每个状态表示容量为j(j<=m)时选最多的宝物,而一个子节点中只可以选择一个状态进行转移,每个节点有若干个子节点,问题就转换为分组背包,几个子节点就是几个分组背包,体积是选几个地点,价值是宝物价值. 状态转移方程: dp[v][1] = Money[v]; (v为叶子节点)                    dp[v][j] = m

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

hdu 3033(好题,分组背包)

I love sneakers! Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 4919    Accepted Submission(s): 2022 Problem Description After months of hard working, Iserlohn finally wins awesome amount of sc

hdu 4003 树形dp+分组背包

题意:求K个机器人从同一点出发,遍历所有点所需的最小花费 链接:点我 Sample Input 3 1 1 //3个点,从1出发,1个机器人 1 2 1 1 3 1 3 1 2 1 2 1 1 3 1 Sample Output 3 2 转移方程: dp[i][j]=min(dp[i][j],dp[i][j*k],dp[son[i]][k]+len(i,son[i])*k) 方程还是比较好写的,主要是要遍历所有的点 下面我们分析一下第一个样例 1 / \ / \ 2 3 我们派了一个机器人去3,

hdu 4003 树形dp+分组背包 2011大连赛区网络赛C

题意:求K个机器人从同一点出发,遍历所有点所需的最小花费 链接:点我 Sample Input 3 1 1 //3个点,从1出发,1个机器人 1 2 1 1 3 1 3 1 2 1 2 1 1 3 1 Sample Output 3 2 转移方程: dp[i][j]=min(dp[i][j],dp[i][j*k],dp[son[i]][k]+len(i,son[i])*k) 方程还是比较好写的,主要是要遍历所有的点 下面我们分析一下第一个样例 1 / \ / \ 2 3 我们派了一个机器人去3,

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