Ural Championship 2013 H E-Lite
2016-07-17 21:36
155 查看
E-Lite
Time limit: 2.0 second Memory limit: 64 MB
The developers of the e-Lite game made it possible for each player to
adjust the parameters of his spaceship as he wants. Initially each
player has a spaceship with n empty slots on its body. The player can
either put up a jet engine in a slot or use this slot for a cargo
module. Each slot can be used for an engine of a specific type, i.e.,
with a certain direction and power. The spaceship’s controlling system
is designed so that all the engines can be either simultaneously
turned on at full power or simultaneously turned off. If the engines
accelerate the spaceship in different directions, it can happen that
the installation of all the engines imparts to the spaceship a smaller
acceleration than the installation of only a part of them. That is why
a player should think where to install engines to get the maximum
acceleration.
Input
The first line contains the number n (1 ≤ n ≤ 1 000) of empty slots on the spaceship’s body. The i-th of the following n lines contains integers xi and yi (−106 ≤ xi, yi ≤ 106), which are the coordinates of the vector of acceleration imparted to the ship by the i-th engine.
Output
For each i from 1 to n, output in a separate line the value of the maximum acceleration of a ship with exactly i engines. The absolute or relative error of each answer should not exceed 10−6. Sample
input
3
3 -2
-3 -2
0 4
output
4.000000
4.000000
0.000000
题目简述:有n个向量,求k(k=1,2…n)个向量合成的最长向量长度。
对于一个答案向量,合成它的向量必然是在答案向量上投影最长的k个向量。可以枚举答案向量方向,将已知向量关于在答案向量的投影排序,取前k个向量和更新答案ans[k]。
有个更有正确性保证但代码复杂度更高的方法:将两两向量和的垂直平分线列举出来作为决策点,开始假设答案向量在x轴正半轴方向,对于答案向量每个给定向量都有一个贡献的排名rank[i],每当转过一个决策点,决策点的两个向量rank会交换,不断维护这个rank和当前答案,取最优便可得到最后答案。
麻烦之处就在于重合向量的处理,具体处理参见以下程序:
Time limit: 2.0 second Memory limit: 64 MB
The developers of the e-Lite game made it possible for each player to
adjust the parameters of his spaceship as he wants. Initially each
player has a spaceship with n empty slots on its body. The player can
either put up a jet engine in a slot or use this slot for a cargo
module. Each slot can be used for an engine of a specific type, i.e.,
with a certain direction and power. The spaceship’s controlling system
is designed so that all the engines can be either simultaneously
turned on at full power or simultaneously turned off. If the engines
accelerate the spaceship in different directions, it can happen that
the installation of all the engines imparts to the spaceship a smaller
acceleration than the installation of only a part of them. That is why
a player should think where to install engines to get the maximum
acceleration.
Input
The first line contains the number n (1 ≤ n ≤ 1 000) of empty slots on the spaceship’s body. The i-th of the following n lines contains integers xi and yi (−106 ≤ xi, yi ≤ 106), which are the coordinates of the vector of acceleration imparted to the ship by the i-th engine.
Output
For each i from 1 to n, output in a separate line the value of the maximum acceleration of a ship with exactly i engines. The absolute or relative error of each answer should not exceed 10−6. Sample
input
3
3 -2
-3 -2
0 4
output
4.000000
4.000000
0.000000
题目简述:有n个向量,求k(k=1,2…n)个向量合成的最长向量长度。
对于一个答案向量,合成它的向量必然是在答案向量上投影最长的k个向量。可以枚举答案向量方向,将已知向量关于在答案向量的投影排序,取前k个向量和更新答案ans[k]。
#include <cstdio> #include <algorithm> #include <iostream> #include <cmath> using namespace std; typedef double db; const int maxn = 1e3 + 5; const int m = 1e4; const db pi = acos(-1.0); int n, rnk[maxn]; db vx[maxn], vy[maxn], ans[maxn], ux, uy; bool cmp(int i, int j){ return vx[i] * ux + vy[i] * uy > vx[j] * ux + vy[j] * uy; } int main(){ scanf("%d", &n); for(int i = 1; i <= n; ++i) scanf("%lf%lf", &vx[i], &vy[i]); for(int i = 1; i <= n; ++i) rnk[i] = i; for(int i = 1; i <= m; ++i){ db ang = 2.00 * pi / m * (i - 1); ux = cos(ang); uy = sin(ang); sort(rnk + 1, rnk + n + 1, cmp); db tx = 0, ty = 0; for(int j = 1; j <= n; ++j){ tx += vx[rnk[j]]; ty += vy[rnk[j]]; ans[j] = max(ans[j], tx * tx + ty * ty); } } for(int i = 1; i <= n; ++i) printf("%.10f\n", sqrt(ans[i])); return 0; } //Thanks to XYT
有个更有正确性保证但代码复杂度更高的方法:将两两向量和的垂直平分线列举出来作为决策点,开始假设答案向量在x轴正半轴方向,对于答案向量每个给定向量都有一个贡献的排名rank[i],每当转过一个决策点,决策点的两个向量rank会交换,不断维护这个rank和当前答案,取最优便可得到最后答案。
麻烦之处就在于重合向量的处理,具体处理参见以下程序:
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #include<cassert> #include<map> #define rank rrrr using namespace std; typedef long double LD; const int N = 1010; const LD pi = acos(-1); const LD eps = 1e-12; map<pair<int,int>,int >mm; int n, xx , yy ; LD Sqrt(LD x){ return x < eps ? 0 : sqrt(x); } struct Point{ LD x,y; int num; Point(){} Point(LD x, LD y):x(x),y(y){} LD length(){ return x * x + y * y; } }p ; Point operator - (const Point &a, const Point &b){ return Point(a.x - b.x, a.y - b.y); } Point operator + (const Point &a, const Point &b){ return Point(a.x + b.x, a.y + b.y); } Point operator * (const Point &a, const LD &k){ return Point(a.x * k, a.y * k); } LD dot(const Point &a, const Point &b){ return a.x * b.x + a.y * b.y; } int rank , id ; int cnt ; LD key ; Point sum ; LD ans ; struct Node{ LD ang; int p, q; Node(){} Node(LD ang, int p, int q):ang(ang), p(p), q(q){} }a[N * N]; bool cmp_angle(const Node &a, const Node &b){ return a.ang < b.ang; } bool cmp_id(const Node &a, const Node &b){ if(rank[a.p] != rank[b.p]) return rank[a.p] < rank[b.p]; return rank[a.q] < rank[b.q]; } void initial_sort(){ //Point vec(cos(ang), sin(ang)); for(int i=1;i<=n;i++){ id[i] = i; } for(int i=1;i<=n;i++) for(int j=i+1;j<=n;j++) if(!(xx[id[i]] < xx[id[j]] || (xx[id[i]]==xx[id[j]] && yy[id[i]] < yy[id[j]]))){ swap(id[i], id[j]); } sum[0] = Point(0,0); cnt[0] = 0; int now = 0; for(int i=1;i<=n;i++){ for(int j=1;j<=p[id[i]].num;j++) { now++; sum[now] = sum[now-1] + p[id[i]]; ans[now] = sum[now].length(); rank[id[i]] = i; } cnt[i] = now; } } void work(int pre, int la){ assert(rank[pre] == rank[la] - 1); int k = rank[pre]; int now = cnt[k-1]; for(int i=1;i<=p[la].num;i++){ now++; sum[now] = sum[now - 1] + p[la]; ans[now] = max(ans[now], sum[now].length()); } cnt[k] = now; for(int i=1;i<=p[pre].num;i++){ now++; sum[now] = sum[now-1] + p[pre]; ans[now] = max(ans[now], sum[now].length()); } swap(rank[pre], rank[la]); } int main(){ cin>>n; int n_bak = n; for(int i=1;i<=n;i++){ scanf("%d%d", &xx[i], &yy[i]); p[i] = Point(xx[i],yy[i]); mm[make_pair(xx[i],yy[i])] ++;; } n = 0; for(map<pair<int,int>, int>::iterator it = mm.begin();it!=mm.end();it++){ n++; xx = (it -> first).first; yy = (it -> first).second; p = Point(xx , yy ); p .num = it -> second; } int num = 0; for(int i=1;i<=n;i++) for(int j=i+1;j<=n;j++) if(xx[i]!=xx[j] || yy[i] != yy[j]) { a[++num] = Node(atan2(xx[j] - xx[i], yy[i] - yy[j]), j, i);//j is defeated by i a[++num] = Node(atan2(-xx[j] + xx[i], -yy[i] + yy[j]), i, j); } sort(a+1, a+num+1, cmp_angle); initial_sort(); for(int i=1,j;i<=num;i=j){ for(j = i+1; fabs(a[i].ang - a[j].ang) < eps && j<=num;j++); sort(a+i, a+j, cmp_id); for(int k=i;k<j;k++){ work(a[k].p, a[k].q); } } for(int i=1;i<=n_bak;i++) printf("%.8f\n",(double)Sqrt(ans[i])); } //Thanks to XZJ
相关文章推荐
- 初学算法 - 求凸包的Garham's Scan算法的C++实现
- 【Google Code Jam 2009 round2 problem D】Watering Plants (两圆交点求法详解)
- 计算几何模板
- 计算几何小模板
- BZOJ2829信用卡凸包
- HDU 4922 Hello, Your Package! (计算几何+DP)(WA)
- poj 1514&zoj 1185 Metal Cutting(半平面交)
- UVA 10969 Sweet Dream(圆的相交)
- uva 11177 Fighting Against a Polygonal Monster(凸包与圆的面积交)
- POJ1279 && LA2512 Art Gallery(求多边形的核)
- poj 2540 && uva 10084 Hotter Colder(半平面交)
- UVALive 5878 - Shortest Leash 【计算几何】
- 【计算几何】POJ 2318 & POJ 2398
- 【计算几何】POJ 2653
- 【计算几何】POJ 1113
- HDU 5128 The E-pang Palace
- POJ 2318 TOYS(叉积+二分or暴力)
- POJ 2398 Toy Storage(叉积+二分)
- POJ 1228 Grandpa's Estate 计算凸包+判断点在线段上
- POJ 1873 The Fortified Forest 计算凸包