题意:矿工起初在(0,0)位置,有n种金矿,给出每种金矿的坐标,花费时间和价值。在同一条线上的金矿必须先抓近的再抓远的,若近的不抓没办法抓远的。要求在T时间内获得的最大价值。
完全没有想到使用分组背包来做哎... 你可以这样想,同一斜率下的金矿看成一组,只能选一个。其实明明可以都抓到,为啥只能选一个。因为如果你想拿后面的,前面的必须拿到。所以我们处理一下,拿到第二个的花费和价值都加上第一个的。以此类推。这样保证我们同一斜率下只能拿一个。但是拿这0一个,我们的支出和收入是很多个的。
- #include <stdio.h>
- #include <string.h>
- #include <algorithm>
- #include <vector>
- using namespace std;
- int n,T;
- struct node
- {
- int x,y;
- int t,v;
- bool operator < (const struct node &tmp)const
- {
- if(y*tmp.x == x*tmp.y)
- return y < tmp.y;
- return y*tmp.x < x*tmp.y;
- }
- }point[210];
- vector <struct node> edge[210];
- int cnt;
- int dp[40010];
- int solve()
- {
- memset(dp,0,sizeof(dp));
- for(int i = 0; i <= cnt; i++)
- {
- for(int j = T; j >= edge[i][0].t; j--)
- {
- for(int k = 0; k < (int)edge[i].size(); k++)
- dp[j] = max(dp[j], dp[j-edge[i][k].t]+edge[i][k].v);
- }
- }
- return dp[T];
- }
- int main()
- {
- int item = 1;
- while(~scanf("%d %d",&n,&T))
- {
- for(int i = 0; i < n; i++)
- scanf("%d %d %d %d",&point[i].x,&point[i].y,&point[i].t,&point[i].v);
- sort(point,point+n);
- for(int i = 0; i < n; i++)
- edge[i].clear();
- cnt = 0;
- edge[cnt].push_back(point[0]);
- for(int i = 1; i < n; i++)
- {
- if(point[i].x*point[i-1].y == point[i].y*point[i-1].x)
- edge[cnt].push_back(point[i]);
- else edge[++cnt].push_back(point[i]);
- }
- for(int i = 0; i <= cnt; i++)
- {
- for(int j = 1; j < (int)edge[i].size(); j++)
- {
- edge[i][j].t += edge[i][j-1].t;
- edge[i][j].v += edge[i][j-1].v;
- }
- }
- printf("Case %d: %d\n",item++,solve());
- }
- return 0;
- }