Guard Duty (hard) Codeforces - 958E3 || uva 1411

https://codeforces.com/contest/958/problem/E3

当没有三点共线时,任意一个这样的点集都是保证可以找到答案的,(考虑任意一种有相交的连线方案,一定可以将其中两条相交的连线改成不相交的,并使得连线的总长度变小;显然连线的总长度最小的方案一定存在,则这种方案一定没有连线相交)

因此可以有一个分治做法:先在当前点集中找出最左、最下的点,找出一个点与其配对,使得以这两点间连线所在的直线划分开点集后,两边各自都满足白点数等于黑点数;显然一定能找到这个与其配对的点

找的方法就是其他点以选出这个点为中心做极角排序,然后双指针

复杂度n^2*log

本来以为分治时可以随便找出一个点,但事实上这样不对的,举个例子:

(以A2为选出点,则找不到配对点)

 

  1 #include<cstdio>
  2 #include<algorithm>
  3 #include<cstring>
  4 #include<vector>
  5 #include<cmath>
  6 using namespace std;
  7 #define fi first
  8 #define se second
  9 #define mp make_pair
 10 #define pb push_back
 11 typedef long long ll;
 12 typedef unsigned long long ull;
 13 typedef pair<int,int> pii;
 14 namespace X
 15 {
 16     struct Point
 17     {
 18         int x,y;
 19         Point(int x=0,int y=0):x(x),y(y){}
 20     };
 21     typedef Point Vec;
 22     Vec operator+(const Vec& a,const Vec& b)
 23     {
 24         return Vec(a.x+b.x,a.y+b.y);
 25     }
 26     Vec operator-(const Vec& a,const Vec& b)
 27     {
 28         return Vec(a.x-b.x,a.y-b.y);
 29     }
 30     int dcmp(int x)
 31     //正为1,负为-1,0为0
 32     {
 33         if(x==0)    return 0;
 34         return x<0?-1:1;
 35     }
 36     bool operator==(const Vec& a,const Vec& b)
 37     //判向量相等
 38     {
 39         return dcmp(a.x-b.x)==0&&dcmp(a.y-b.y)==0;
 40     }
 41     double cross(const Vec& a,const Vec& b)
 42     //叉积
 43     {
 44         return a.x*b.y-a.y*b.x;
 45     }
 46 };
 47 using namespace X;
 48 Point p[20100];
 49 int an[10100];
 50 int d[20100],tmp[20100];
 51 int n;
 52 double ang[20100];
 53 bool vis[20100];
 54 bool c1(int a,int b)
 55 {
 56     return ang[a]<ang[b];
 57 }
 58 bool c2(int a,int b)
 59 {
 60     return p[a].x<p[b].x||(p[a].x==p[b].x&&p[a].y<p[b].y);
 61 }
 62 void solve(int l,int r)
 63 {
 64     if(r<l)    return;
 65     swap(*min_element(d+l,d+r+1,c2),d[l]);
 66     int i;
 67     for(i=l+1;i<=r;i++)
 68         ang[d[i]]=atan2(p[d[i]].y-p[d[l]].y,p[d[i]].x-p[d[l]].x);
 69     sort(d+l+1,d+r+1,c1);
 70     int len=r-l,a[]={0,0},nl,nr;
 71     for(nl=l+1,nr=l;nl<=r;nl++)//包含(nl,nr]的点,nl自身与l相连
 72     {
 73         while(nr<nl||(nr-nl+1<len&&cross(p[d[(nr-l)%len+l+1]]-p[d[l]],p[d[nl]]-p[d[l]])<0))
 74         {
 75             ++nr;
 76             a[d[(nr-l-1)%len+l+1]<=n]++;
 77         }
 78         a[d[nl]<=n]--;
 79         if(int(d[nl]<=n)+(d[l]<=n)==1&&a[0]==a[1])    break;
 80     }
 81     if(d[l]<=n)    an[d[l]]=d[nl];
 82     else    an[d[nl]]=d[l];
 83     for(i=l+1;i<=r;i++)
 84         vis[i]=0;
 85     vis[nl]=1;
 86     tmp[0]=0;
 87     for(i=nl+1;i<=nr;i++)
 88     {
 89         vis[(i-l-1)%len+l+1]=1;
 90         tmp[++tmp[0]]=d[(i-l-1)%len+l+1];
 91     }
 92     int t1=l;
 93     for(i=l+1;i<=r;i++)
 94         if(!vis[i])
 95         {
 96             d[++t1]=d[i];
 97         }
 98     int t2=t1;
 99     for(i=1;i<=tmp[0];i++)
100         d[++t2]=tmp[i];
101     solve(l+1,t1);solve(t1+1,t2);
102 }
103 int main()
104 {
105     int i;
106     while(scanf("%d",&n)==1)
107     {
108     for(i=1;i<=2*n;i++)    scanf("%d%d",&p[i].x,&p[i].y);
109     for(i=1;i<=2*n;i++)    d[i]=i;
110     solve(1,2*n);
111     for(i=1;i<=n;i++)    printf("%d\n",an[i]-n);
112     }
113     return 0;
114 }
View Code

 

双倍经验:https://vjudge.net/problem/UVA-1411

 

posted @ 2018-09-27 10:06  hehe_54321  阅读(291)  评论(0编辑  收藏  举报
AmazingCounters.com