@lychee123
2017-08-16T20:53:43.000000Z
字数 1620
阅读 1052
计算几何
题意
在一个二维平面上有n个星星
每个星星有坐标和价值
这些星星可以两两连成一条线段。这条线段的价值为这两个星星价值的乘积。我们保证了不会有两两连线穿过坐标原点。我们需要找到一条线 。并且穿过这条直线的线段的总价值最大。
样例
Sample Input
2 // 多组输入
2
1 1 1
1 -1 1
3
1 1 1
1 -1 10
-1 0 100Sample Output
1
1100
分析
首先将每个星星的与轴正方向的夹角算出来然后从小到大排序。
角度怎么算呢?这里是有自带函数的。,求的向量与轴正方向夹角的弧度。返回值为。
const double pi = acos(-1.0); 使用常量定义
a[i].jiaodu=atan2(a[i].y,a[i].x)*180/pi;
这样算出来的角度范围为。
时是正角度, 时是负角度
if(a[i].jiaodu<0)
a[i].jiaodu+=360;//将角度转换成 0°到180°
我们循环这些按角度排好序的星星。找到第一个他们差值大与180°的星星编号。将这个星星作为分界点。相当于此时我们就找到了一条直线将他们分成了两部分。上部分从循环点开始到分界点的上一个点。剩下的为下部分。上部分和下部分的点两两相连则求出穿过这条直线的所有线段的价值。其实就是对上部分求和为 ,下部分求和为 。对所有的ans求个最大值就好了
将长度为n的求和数组拷贝为2n的长度,每次截取的n长度的片段都是一个完整的片段。
对于两部分的求和
将这2n个val求个前缀和
代码
#include<bits/stdc++.h>
using namespace std;
const int maxn=5e4+5;
#define pi acos(-1.0)
struct node
{
int x,y,val;
double jiaodu;
friend bool operator < (const node &A,const node &B)//按结构体内某一元素排序,这样之后直接sort就OK了,不用加cmp
{
return A.jiaodu<B.jiaodu;
}
/** 另一种写法
bool operator < (const node &B) const
{
return jiaodu < B.jiaodu;
}
**/
}a[2*maxn];
long long sum[2*maxn];
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
int n;
scanf("%d",&n);
for(int i=0;i<n;i++)
{
scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].val);
a[i].jiaodu=atan2(a[i].y,a[i].x)*180/pi;
if(a[i].jiaodu<0)
a[i].jiaodu+=360;
}
sort(a,a+n);
for(int i=0;i<n;i++)
{
a[i+n]=a[i];
a[i+n].jiaodu+=360;
}
sum[0]=a[0].val;
for(int i=1;i<2*n;i++)
sum[i]=sum[i-1]+a[i].val;
int pos=0;
long long ans=0;
for(int i=0;i<n;i++)
{
while(a[pos].jiaodu-a[i].jiaodu<180)
pos++;
long long l=sum[i+n-1]-sum[pos-1];
long long r=sum[pos-1]-sum[i-1];
ans=max(ans,l*r);
}
printf("%lld\n",ans);
}
return 0;
}