HDOJ-4341(分组DP)

经典的分组DP题:


#include <cstdio>
#include <vector>
#include <map>
#include <algorithm>
using namespace std;
#define MAXN    200
#define MAXT    40000

struct Line{
    int a, b;//ax = by
    Line(){}
    Line(int aa, int bb) : a(aa), b(bb){}
    friend bool operator < (const Line& p, const Line& q){
        return p.a != q.a ? p.a < q.a : p.b < q.b;
    }
};
struct Gold{
    int x, y, t, v;
    Gold(){}
    Gold(int X, int Y, int T, int V) : x(X), y(Y), t(T), v(V){}
    friend bool operator < (const Gold& a, const Gold& b){
        return a.y < b.y;
    }
};
vector<Gold> lineGold[MAXN+1];
int lineCount;
int dp[MAXN+1][MAXT+1];

int gcd(int a, int b)
{
    if(a < b) swap(a, b);
    while(b){
        int t = a % b;
        a = b;
        b = t;
    }
    return a;
}
Line getLine(int x, int y)
{
    if(x == 0) return Line(0, 1);
    int d = gcd(x > 0 ? x : -x, y);
    return Line(y / d, x / d);
}

int main()
{
    int test = 0, N, T;
    int x, y, t, v;
    Line l;
    map<Line, vector<Gold>*> goldMap;
    map<Line, vector<Gold>*>::iterator iter, eter;

    while(scanf("%d%d", &N, &T) == 2){
        ++test;
        lineCount = 0;
        goldMap.clear();
    //step 1: input gold info and divide them into groups
        for(int i = 0; i < N; ++i){
            scanf("%d %d %d %d", &x, &y, &t, &v);
            iter = goldMap.find(l = getLine(x, y));
            if(iter == goldMap.end()){
                ++lineCount;
                lineGold[lineCount].clear();
                lineGold[lineCount].push_back(Gold(x, y, t, v));
                goldMap.insert(map<Line, vector<Gold>*>::value_type(l, &lineGold[lineCount]));
            }
            else iter->second->push_back(Gold(x, y, t, v));
        }
    //special judge
        if(N == 0 || T == 0){
            printf("Case %d: 0\n", test);
            continue;
        }
    //step 2: sort each group up, get all choices of each group
        for(iter = goldMap.begin(), eter = goldMap.end(); iter != eter; ++iter){
            sort(iter->second->begin(), iter->second->end());
            vector<Gold>& v = *(iter->second);
            for(int i = 1, s = v.size(); i < s; ++i){
                v[i].t += v[i-1].t;
                v[i].v += v[i-1].v;
            }
        }
    //step 3: backpack
        for(int n = 0; n <= lineCount; ++n) dp[n][0] = 0;
        for(int t = 0; t <= T; ++t) dp[0][t] = 0;
        for(int n = 1; n <= lineCount; ++n){
            for(int t = 1; t <= T; ++t){
                dp[n][t] = dp[n-1][t];
                const vector<Gold>& v = lineGold[n];
                for(int i = 0, s = v.size(); i < s; ++i){
                    if(t >= v[i].t) dp[n][t] = max(dp[n][t], v[i].v + dp[n-1][t-v[i].t]);
                    else break;
                }
            }
        }
        printf("Case %d: %d\n", test, dp[lineCount][T]);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值