【GDOI2018模拟7.6】仰望星空

来源:互联网 发布:国企混日子 知乎 编辑:程序博客网 时间:2024/04/27 14:59

Description

由于原题看了好多遍才真正理解题意,这里讲一个简化版本
给出平面上的一个圆和n个点
现在要再这n个点之间两两连边
每个点只能被连一次,只有圆内和圆外之间距离不超过d的点可以互相连边
且如果存在三个圆内的未被连边的点x,y,z,与圆外一点w的距离不超过d
现在若想连接w和y,并且x与z的连线与w,y的连线相交,那么这个连线是不合法的
求最大的连线数目和方案
n<=1e3

Solution

显然最大匹配
考虑怎么处理这个鬼畜的限制
发现执行匈牙利算法的时候我们每个点都会按顺序匹配
于是我们队每个圆外的点,将圆内的点关于它做一次极角排序,得到它的遍历顺序
然后直接做匈牙利就可以解决这个神奇的限制得到答案
注意方案必须要按顺序,所以每个点必须等它之前的匹配全部输出之后才能输出

并不知道atan2用来极角排序哪里错了

bool cmp(point a,point b) {return atan2(a.y-rt.y,a.x-rt.x)<atan2(b.y-rt.y,b.x-rt.x);}

改成叉积就对了,求dalao解释

bool cmp(point a,point b) {return cro(a,b,rt)>0;}

UPD:错因很显然然而我现在才发现一定是我太弱了_ (:з」∠) _
这道题排极角序必须是严格按顺序,不能有一个起点
然而用atan2就默认第3象限最小,这样会有问题

Code

#include <cmath>#include <cstdio>#include <cstring>#include <algorithm>#define fo(i,a,b) for(int i=a;i<=b;i++)#define sqr(x) (x)*(x)using namespace std;typedef double db;const int N=1e3+5;int n,r,d,tot,ans,b[N],c[N],g[N][N],to[N],link[N];db eps=1e-5;bool vis[N],bz[N];struct point{int x,y,id;}a[N],p[N],rt;int cro(point a,point b,point x) {return (a.x-x.x)*(b.y-x.y)-(a.y-x.y)*(b.x-x.x);}db dist(point a,point b) {return sqrt(sqr(a.x-b.x)+sqr(a.y-b.y));}bool cmp(point a,point b) {return cro(a,b,rt)>0;}int find(int x) {    fo(i,1,g[x][0])         if (!vis[g[x][i]]) {            vis[g[x][i]]=1;            if (!to[g[x][i]]||find(to[g[x][i]])) {                to[g[x][i]]=x;                return 1;            }        }    return 0;}int main() {    freopen("B.in","r",stdin);    scanf("%d%d%d",&n,&r,&d);    fo(i,1,n) scanf("%d%d",&a[i].x,&a[i].y),a[i].id=i;    fo(i,1,n) {        if (dist(a[i],a[1])-r<eps) b[++b[0]]=i;        else c[++c[0]]=i;    }    fo(i,1,c[0]) {        tot=0;rt=a[c[i]];        fo(j,1,b[0])             if (dist(a[b[j]],a[c[i]])-d<eps)                 p[++tot]=a[b[j]];        sort(p+1,p+tot+1,cmp);int x=a[c[i]].id;        fo(j,1,tot) g[x][++g[x][0]]=p[j].id;    }    fo(i,1,c[0]) {        memset(vis,0,sizeof(vis));        ans+=find(a[c[i]].id);    }    printf("%d\n",ans*2);    fo(i,1,b[0]) link[to[a[b[i]].id]]=a[b[i]].id;    fo(i,1,ans) {        bool pd=0;int now=0;        fo(j,1,c[0]) {            int x=a[c[j]].id;            fo(k,1,g[x][0])                 if (!bz[g[x][k]]) {                    if (g[x][k]==link[x]) pd=1;                    now=g[x][k];break;                }            if (pd) {                bz[now]=1;                printf("%d %d\n",x,now);                break;            }        }    }}
原创粉丝点击