先把线按照距离原点的距离排序,然后用叉积把在同一条直线上的点放在一起,
把在同一条线上的点中的前i个点当成一个点就转化成了分组背包。
写if(kas++) putchar(' ') 居然PE了,PE选手
#include<bits/stdc++.h> using namespace std; int N,T; const int maxn = 203; const int MAXT = 40005; struct Point { int x,y,t,v; }P[maxn]; bool vis[maxn]; vector<int> Line[maxn]; int Line_cnt; #define PB push_back int Dot(const Point &a,const Point& b) { return a.x*b.x+a.y*b.y; } double Length(const Point &x) { return sqrt(Dot(x,x)); } int Cross(Point &a,Point &b) { return a.x*b.y-b.x*a.y; } bool operator < (const Point& a,const Point & b) { return Length(a)<Length(b); } void init() { memset(vis,0,sizeof(vis)); for(int i = 0; i < N; i++){ scanf("%d%d%d%d",&P[i].x,&P[i].y,&P[i].t,&P[i].v); } sort(P,P+N); Line_cnt = 0; for(int i = 0; i < N; i++)if(!vis[i]){ Line[Line_cnt].clear(); for(int j = i; j < N; j++)if(!vis[j]){ if(Cross(P[i],P[j]) == 0){ vis[j] = true; Line[Line_cnt].PB(j); } } Line_cnt++; } } int f[2][MAXT]; void dp() { fill(f[0],f[0]+1+T,0); fill(f[1],f[1]+1+T,0); for(int i = 0; i < Line_cnt; i++){ int pre = i&1,cur = pre^1; int totV = 0, totT = 0; for(int j = 0; j < Line[i].size(); j++){ Point& x = P[Line[i][j]]; totV += x.v; totT += x.t; for(int k = T; k >= totT; k--){ f[cur][k] = max(f[cur][k],f[pre][k-totT]+totV); } } for(int k = 0; k <= T; k++){ f[cur][k] = max(f[cur][k],f[pre][k]); } } } int main() { int kas = 0; while(~scanf("%d%d",&N,&T)){ init(); dp(); printf("Case %d: %d ",++kas,max(f[0][T],f[1][T])); } return 0; }
当时并不知道如何用一维数组实现,补上一维的伪代码
for 所有的组k
for v=V..0 //从大到小枚举V
for 所有的i属于组k
f[v]=max{f[v],f[v-c[i]]+w[i]}//从小的V转移,是上一组的状态