题意:
黄金矿工,在时间T内,在给定的矿石中获得其中部分矿石的最大价值和。
如果矿石在同一条线上,要先把线上的前面的矿石拿走,才可以接着拿后面的矿石。
题解:
把每个矿石的斜率求出来,当斜率相同,就是在同一条直线上了。因为横坐标可能为0.所以求的是斜率的倒数。
对于数据中的每个斜率,就为一组物品。每组物品要么取一个,要么取两个。。。。
#pragma GCC optimize(2,"Ofast","inline")
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<string>
#include<vector>
#include<cstring>
#include<queue>
#include<stack>
#include<list>
#include<map>
#include<set>
#include<cmath>
#include<sstream>
#include<cstdlib>
#include<bitset>
#include<functional>
#include<ctime>
#define F(i,s,t) for(int i=(s);i<=(t);i++)
#define D(i,s,t) for(int i=(s);i>=(t);i--)
#define dBug(i) printf("Value=%d\n",i)
#define ddBug(i,j) printf("Value=%d %d\n",i,j)
#define ed putchar('\n')
#define FO freopen("D:\\in.txt","r",stdin)
#define IOS cin.tie(0) ,cout.tie(0), cout.sync_with_stdio(0)
typedef long long ll;
//const int INF = 1 << 30;
//const double EPS = 1e-6;
//#define MX 1002
//#define Mod 10000
using namespace std;
struct Mineral
{
int x, y, t, v;
};
int N, T;
double t1, t2;//t1表示a的斜率
Mineral M[210];
vector<Mineral> G[210];//用于存第i组的矿石
int dp[40010];
bool cmp(Mineral &a, Mineral &b)//按斜率的倒数降序排序
{
t1 = (double)a.x / a.y;
t2 = (double)b.x / b.y;
if (t1 != t2)//当斜率不同时
return t1 < t2;
else{ // 当a和b 矿山在同一直线上
t1 = a.x * a.x + a.y * a.y; //按离原点的远近升序排序
t2 = b.x * b.x + b.y * b.y;
return t1 < t2;
}
}
int main()
{
IOS;
//FO;
int cas(0);//用于记录第几组数据
while (scanf("%d %d", &N, &T) != EOF){
memset(dp, 0, sizeof(dp));//初始化
F(i, 1, N) G[i].clear();//初始化
F(i, 1, N)
scanf("%d %d %d %d", &M[i].x, &M[i].y, &M[i].t, &M[i].v);
sort(M + 1, M + N + 1, cmp);//对矿石进行排序
/*cout << endl; ed;
F(i, 1, N)
cout << M[i].x << " " << M[i].y << " "
<< M[i].t << " " << M[i].v << endl;
ed; ed;*/
//下面进行矿石分组
int Group(1);//用于存组数,初始值为1,因为从2号矿石开始的
G[Group].push_back(M[1]);
t1 = (double)M[1].x / M[1].y; //在这里t1表示上一号矿石的斜率
F(i, 2, N){
t2 = (double)M[i].x / M[i].y;
if (t1 != t2){ //当矿石不在同一直线上
Group++;
G[Group].push_back(M[i]);
}//if
else{//当矿石在同一直线上,组号不用加1了,用上次的组号就好
M[i].t += M[i - 1].t;//要改一下时间和价值
M[i].v += M[i - 1].v;
G[Group].push_back(M[i]);
}
t1 = t2;
}//for
/*cout << endl; ed;
F(i, 1, Group){
cout << i << "组"; ed;
F(j, 0, G[i].size() - 1){
cout << G[i][j].x << " " << G[i][j].y << " "
<< G[i][j].t << " " << G[i][j].v << endl;
}
}
ed; ed;*/
//下面是分组背包了
F(i, 1, Group)//枚举分组
D(j, T, 1)//枚举时间
F(k, 0, G[i].size() - 1){ //枚举组里面每一个价值
if (j >= G[i][k].t)//背包可以装第i组的第k个物品
dp[j] = max(dp[j], dp[j - G[i][k].t] + G[i][k].v);
}//inner for
printf("Case %d: %d\n", ++cas, dp[T]);
}//while
}