您的位置:首页 > 其它

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]。

#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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  计算几何 精妙