【极角排序+双指针线性扫】2017多校训练七 HDU 6127 Hard challenge

acm.hdu.edu.cn/showproblem.php?pid=6127

【题意】

  • 给定平面直角坐标系中的n个点,这n个点每个点都有一个点权
  • 这n个点两两可以连乘一条线段,定义每条线段的权值为线段两端点点权的乘积
  • 现在要过原点作一条直线,要求这条直线不经过任意一个给定的点
  • 在所有n个点两两连成的线段中,计算与这条直线有交点的线段的权值和
  • 最大化这个权值和并输出
  • 题目保证,给定的n个点不重合且任意两个点的连线不经过原点

【思路】

  • 一条经过原点的直线把n个点分成两个半平面A,B
  • 假设A中的点权分别为a1,a2....an;B中的点权分别为b1,b2,......bm。则结果为sumA*sumB
  • 极角排序,枚举每个起点,线性扫一圈,计算半平面的点权之和,不断更新最优值

【AC】

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<string>
 5 #include<cmath>
 6 #include<algorithm>
 7 
 8 using namespace std;
 9 typedef long long ll;
10 const int maxn=5e4+2;
11 int n;
12 double xx[maxn];
13 double yy[maxn];
14 ll val[maxn];
15 ll ans[maxn];
16 
17 double dis(double x1,double y1,double x2,double y2){return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));}
18 const double eps = 1e-6;
19 struct Point
20 {
21     double x;
22     double y;
23     ll val;
24     double dis;
25     double alf; 
26     Point(){}
27     Point(double _x,double _y):x(_x),y(_y){}
28     Point(double _x,double _y,ll _val):x(_x),y(_y),val(_val){}
29     Point operator -(const Point &t) const
30     {
31         return Point(x-t.x,y-t.y);
32     }
33     double operator ^(const Point &t)const
34     {
35         return (x*t.y)-(y*t.x);
36     }
37 }p[maxn];
38 Point o(0.0,0.0);
39 bool cmp(const Point &a, const Point &b)//先按象限排序,再按极角排序,再按远近排序 
40 {
41     if (a.y == 0 && b.y == 0 && a.x*b.x <= 0)return a.x>b.x;
42     if (a.y == 0 && a.x >= 0 && b.y != 0)return true;
43     if (b.y == 0 && b.x >= 0 && a.y != 0)return false;
44     if (b.y*a.y <= 0)return a.y>b.y;
45     return ((a-o)^(b-o))> 0.0 || (((a-o)^(b-o)) == 0.0 && a.x < b.x);    
46 }
47 
48 int main()
49 {
50     int T;
51     scanf("%d",&T);
52     while(T--)
53     {
54         memset(ans,0,sizeof(ans));
55         scanf("%d",&n);
56         ll sum=0;
57         for(int i=0;i<n;i++)
58         {
59             scanf("%lf%lf%I64d",&xx[i],&yy[i],&val[i]);
60             p[i]=Point(xx[i],yy[i],val[i]);    
61             sum+=val[i];
62         }   
63         sort(p,p+n,cmp); 
64         int l=1;
65         ll res;
66         ans[0]+=p[0].val;
67         for(int i=0;i<n;i++)
68         {    
69             if(i>0) ans[i]=ans[i-1]-p[i-1].val;
70             while(((p[i]-o)^(p[l]-o))>0)
71             {
72                 ans[i]+=p[l].val;
73                 l=(l+1)%n;     
74             }   
75             if(i==0) res=ans[i]*(sum-ans[i]);
76             else res=max(res,ans[i]*(sum-ans[i]));
77         }
78         printf("%I64d\n",res); 
79     }
80     return 0;
81 }
极角排序+线性扫模板

【模板】

1 bool cmp(const Point &a, const Point &b)//先按象限排序,再按极角排序,再按远近排序 
2 {
3     if (a.y == 0 && b.y == 0 && a.x*b.x <= 0)return a.x>b.x;
4     if (a.y == 0 && a.x >= 0 && b.y != 0)return true;
5     if (b.y == 0 && b.x >= 0 && a.y != 0)return false;
6     if (b.y*a.y <= 0)return a.y>b.y;
7     return ((a-o)^(b-o))> 0.0 || (((a-o)^(b-o)) == 0.0 && a.x < b.x);    
8 }
极角排序,o是中心点
 1    int l=1;
 2         ll res;
 3        // ans[0]+=p[0].val;
 4         for(int i=0;i<n;i++)
 5         {    
 6             //if(i>0) ans[i]=ans[i-1]-p[i-1].val;
 7             while(((p[i]-o)^(p[l]-o))>0)
 8             {
 9                // 必要的运算 
10                 l=(l+1)%n;     
11             }   
12             //这里更新答案 
13         }
线性扫

 

posted @ 2017-08-16 20:20  shulin15  阅读(221)  评论(0编辑  收藏  举报