题意:每个金子有自己的位置,得到所用的时间和价值。要想得到某个金子,必须先得到从原点到目标连线的所有金子。求给出时间内获得的最大价值。
思路:把在同一直线的金子视为一组,对于每个金子,把原点到目标的所有的金子的时间和价值都加到目标上,然后分组背包就不必多说了。
我的代码:
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
const int maxn = 205;
const int maxm = 40005;
struct Node{
int x,y,t,v;
bool operator < (const Node &z) const {
return x*x + y*y < z.x*z.x + z.y*z.y;
}
}gold[maxn],Gd[maxn];
int dp[maxm];
int n,m;
vector<int> G[maxn];
bool vis[maxn];
int len;
void init(){
fill(dp,dp+maxm,0);
fill(vis,vis+maxn,false);
len = 0;
for(int i=0;i<maxn;i++) G[i].clear();
}
void build(){
sort(gold,gold+n);
for(int i=0;i<n;i++){
if(vis[i]) continue;
G[len].push_back(i);
vis[i] = true;
for(int j=i+1;j<n;j++){
if(gold[i].x*gold[j].y == gold[i].y*gold[j].x){
G[len].push_back(j);
vis[j] = true;
}
}
len++;
}
for(int i=0;i<n;i++){
Gd[i] = gold[i];
for(int j=0;j<n;j++){
if(i == j) continue;
if(gold[i].x*gold[j].y == gold[i].y*gold[j].x && gold[i].y > gold[j].y){
Gd[i].t += gold[j].t;
Gd[i].v += gold[j].v;
}
}
}
}
int solve(){
for(int i = 0 ; i < len ; i++){
for(int j = m ; j >= 0 ; j--){
for(int k = 0 ; k < G[i].size() ; k++){
int t = G[i][k];
if(j < Gd[t].t) continue;
dp[j] = max(dp[j],dp[j-Gd[t].t]+Gd[t].v);
}
}
}
return dp[m];
}
int main(){
int cas = 0;
while(~scanf("%d%d",&n,&m)){
init();
for(int i=0;i<n;i++)
scanf("%d%d%d%d",&gold[i].x,&gold[i].y,&gold[i].t,&gold[i].v);
build();
printf("Case %d: %d\n",++cas,solve());
}
return 0;
}