HDU 4341 Gold miner 分组背包变形

8 篇文章 0 订阅

题意:

挖金矿,人在(0,0)点

n个金子 游戏时间为T

下面n行

(x, y) cost val

且若人 和 多块金子共线时,只能先取最近的金子,依次取,就是和游戏一样的。

且所有点只在1 2象限

思路:

我们先把所有共线的点分组

对于每组的物品,我们都可以认为取这个物品的花费就是前面所有物品的花费总和,而价值就是前面所有物品的价值总和。

这样就能消除每组物品的先取后取的影响了,但有一个情况就是这组至多只能取一个物品,所以每个状态只能是取了这个物品后或者是原始状态。

用原始状态转移,然后和原始状态取个最大值。


#include <iostream>
#include <cmath>
#include <algorithm>
#include <cstdio>
#include <map>
#include <vector>
typedef long long ll;
template <class T>
inline bool rd(T &ret) {
    char c; int sgn;
    if(c=getchar(),c==EOF) return 0;
    while(c!='-'&&(c<'0'||c>'9')) c=getchar();
    sgn=(c=='-')?-1:1;
    ret=(c=='-')?0:(c-'0');
    while(c=getchar(),c>='0'&&c<='9') ret=ret*10+(c-'0');
    ret*=sgn;
    return 1;
}
template <class T>
inline void pt(T x) {
    if (x <0) {
        putchar('-');
        x = -x;
    }
    if(x>9) pt(x/10);
    putchar(x%10+'0');
}
const int N = 50000;
using namespace std;
typedef pair<int,int> pii;
int t;
void solve(int T, int V, int *d){
    for(int j = t; j >= T; j --) {
        if(d[j] <= d[j-T] + V)
            d[j] = d[j-T] + V;
    }
}

int n, tim[250], val[250], x[250], y[250], d2[N], st[N];
bool cmp(int a, int b){
    return x[a]*x[a]+y[a]*y[a] < x[b]*x[b]+y[b]*y[b];
}
bool Coline(int a, int b){
    return x[a]*y[b] == x[b]*y[a];
}
vector<int>G[205];
int d[N], top;

void input(){
    for(int i = 1; i <= n; i++) {
        rd(x[i]); rd(y[i]); rd(tim[i]); rd(val[i]);
    }
    top = 0;
    for(int i = 1; i <= n; i++)
    {
        bool yes = false;
        for(int j = 0; j < top && false == yes; j++)
            if(Coline(i, G[j][0]))
            {
                G[j].push_back(i);
                yes = true;
            }
        if(yes)continue;
        G[top].clear(); G[top++].push_back(i);
    }
}
int main(){
    int Cas = 1;;
    while(cin>>n>>t){
        input();
        memset(d, 0, sizeof d);
        for(int i = 0; i < top; i++)
        {
            sort(G[i].begin(), G[i].end(), cmp);
            memcpy(d2, d, sizeof d);
            memcpy(st, d, sizeof d);
            int V = 0, T = 0;
            for(int j = 0; j < G[i].size(); j++)
            {
                solve(T + tim[G[i][j]], V + val[G[i][j]], st);
                T += tim[G[i][j]];
                V += val[G[i][j]];

                for(int k = 0; k <= t; k++)
                    d[k] = max(d[k], st[k]);
                if(T > t) break;
                memcpy(st, d2, sizeof d);
            }
        }
        printf("Case %d: %d\n", Cas++, d[t]);
    }
    return 0;
}
/*
2 2
1 1 1 1
2 2 1 2
3 5
1 1 4 1
2 2 2 100
1 3 4 7
3 8
-1 1 4 2
1 1 5 1
2 2 2 100

3 8
1 1 5 1
2 2 2 100
-1 1 4 2

*/


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值