经典的分组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;
}