HDU 4341 Gold miner 分组背包变形

题意:

挖金矿,人在(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

*/
时间: 2024-10-13 03:14:36

HDU 4341 Gold miner 分组背包变形的相关文章

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

先把线按照距离原点的距离排序,然后用叉积把在同一条直线上的点放在一起, 把在同一条线上的点中的前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 3033 分组背包变形(每种至少一个)

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

hdu 1561 树形dp+分组背包

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

hdu3033---I love sneakers!(分组背包变形)

Problem Description After months of hard working, Iserlohn finally wins awesome amount of scholarship. As a great zealot of sneakers, he decides to spend all his money on them in a sneaker store. There are several brands of sneakers that Iserlohn wan

hdu3033 I love sneakers! 分组背包变形(详解)

这个题很怪,一开始没仔细读题,写了个简单的分组背包交上去,果不其然WA. 题目分析: 分组背包问题是这样描述的:有K组物品,每组 i 个,费用分别为Ci ,价值为Vi,每组物品是互斥的,只能取一个或者不取(最多取一个),求在一定背包容量V的情况下,能够获得的最大价值. 而这个题是,他每个牌子的鞋最少会买一双,但不会买一个牌子同款的两次. 也就是说如果将每个牌子分成一组,那么在每组里面要至少取一双,所以这更像是在每组里面进行01背包. 普通的分组背包的三层循环是: for(int k=0; k<K

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 5534 Partial Tree (完全背包变形)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5534 题意: 给你度为1 ~ n - 1节点的权值,让你构造一棵树,使其权值和最大. 思路: 一棵树上每个节点的度至少为1,且度的和为2*n - 2.那么我们先给这些节点的度都-1,剩下的节点度为n - 2.此时我们发现,任意分配剩下的这些度给节点,都可以形成一棵树.这就变成了一个完全背包题,容量为n-2.注意dp要初始化为-inf.思路确实巧妙. 1 #include <iostream> 2