luogu3961黄金矿工

题意:

从(0,0)点取黄金,黄金的坐标破(x,y),取这个黄金所需时间t,价值v,在与原点同一条连线上的黄金需要先取最近的才能取后面的,求T时间内能获得的最大价值

dp:

首先预处理,求出每个点与原点连线的斜率,按斜率和与原点距离从小到大排序,把斜率相同的点分为一组,预处理出这一组选i个物品所需时间与所得价值,再分组背包dp即可

时间复杂度:

O(nt)

 1 #include<cstdio>
 2 #include<algorithm>
 3 using namespace std;
 4 #define db double
 5 struct node
 6 {
 7     int x,y,t,v;
 8     db k;
 9 }a[2005];
10 bool cmp(node x,node y)
11 {
12     if(x.k == y.k)return x.y < y.y;
13     return x.k < y.k;
14 }
15 int N,T,cnt;
16 int num[2005],v[2005][2005],t[2005][2005];
17 int f[40005];
18 int main()
19 {
20     scanf("%d%d",&N,&T);
21     for(int i= 1;i <= N;i ++)
22     {
23         scanf("%d%d%d%d",&a[i].x,&a[i].y,&a[i].t,&a[i].v);
24         a[i].k = (db)((db)a[i].y / (db)a[i].x);
25     }
26     sort(a + 1,a + 1 + N,cmp);
27     for(int i = 1;i <= N;i ++)
28     {
29         if(a[i].k != a[i - 1].k)cnt ++;
30         num[cnt]++;//如果不写在外面就会80????? 
31         v[cnt][num[cnt]] = v[cnt][num[cnt] - 1] + a[i].v;
32         t[cnt][num[cnt]] = t[cnt][num[cnt] - 1] + a[i].t;
33     }
34     for(int i = 1;i <= cnt;i ++)
35         for(int j = T;j >= t[i][1];j --)
36             for(int k = 1;k <= num[i];k ++)
37                 if(j >= t[i][k])f[j] = max(f[j],f[j - t[i][k]] + v[i][k]);
38     printf("%d\n",f[T]);
39     return 0;
40 }
01-10 10:48