现在的位置: 首页 > 综合 > 正文

hdu 4341 Gold miner(分组背包)

2013年10月06日 ⁄ 综合 ⁄ 共 1258字 ⁄ 字号 评论关闭

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4341

题目大意:小学在4399玩的这游戏。。。就是说在规定时间内,取最多的金子。告诉你每个金子取回来的时间跟位置。

解法:

首先我们可以知道,你在原点处,要勾金子,必然是一条直线下去,如果两块金子斜率相等,你肯定要先把近的那块勾起才能勾远的那块。所以这就相当于背包九讲的一种依赖关系,所以斜率相等的金子可以看成一个物品组,如,1 2 3 4块金子的斜率相等,并且距离递增。那么,我们把这四块放一个组里,DP时,只能取一个,为什么会只能一个?因为如果你要取4,实际上就是1 2 3 4全取了,你只要把第四块金子的价值跟时间把前面几块的都加上就可以了。然后就是分组,然后模板伺候、、、

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
const int maxn=250;
struct node
{
    int x,y,c,v;
    bool operator < (const node &a) const {
        return (y*a.x<a.y*x)||(y*a.x==a.y*x && x*x+y*y<a.x*a.x+a.y*a.y);
        /*斜率优先,斜率相等距离优先*/
    }
}t[maxn];

int n,V;
int dp[41000];

int solve ()
{
    int len=0,ans=0;;
    /*分组*/
    vector <node> group[maxn];
    memset(group,0,sizeof(group));
    group[len].push_back(t[0]);
    int pre=0;
    for(int i=1;i<n;i++)
    {
        if(t[pre].y*t[i].x==t[i].y*t[pre].x){
            t[i].c+=t[pre].c;
            t[i].v+=t[pre].v;
            group[len].push_back(t[i]);
        }
        else{
            group[++len].push_back(t[i]);
        }
        pre=i;
    }
    /*DP*/
    memset(dp,0,sizeof(dp));
    for(int i=0;i<=len;i++)
        for(int j=V;j>=0;j--)
            for(int l=0;l<group[i].size();l++)
                if(j>=group[i][l].c) dp[j]=max(dp[j],dp[j-group[i][l].c]+group[i][l].v);
    return dp[V];
}

int main()
{
    int T=1;
    while (scanf("%d %d",&n,&V)==2)
    {
        for(int i=0;i<n;i++)
            scanf("%d %d %d %d",&t[i].x,&t[i].y,&t[i].c,&t[i].v);
        sort(t,t+n);
        printf("Case %d: %d\n",T++,solve());
    }
    return 0;
}

抱歉!评论已关闭.