【JZOJ5482】第三题
来源:互联网 发布:ppt批量导入照片mac 编辑:程序博客网 时间:2024/06/10 07:21
Description
sl想打dota2了,但他现在在机房,而且yz就在他旁边,他自然不能玩dota2这种这么容易被发现(鼠标、键盘发出啪啪啪的声音,眼睛中射出诡异的光)的游戏,所以他只好打开了一个小游戏。这个小游戏是这样的:在一个平面上有n个A类点(从1~n编号),m个B类点(从1~m编号)。A类点很团结,他们想用n-1条边将他们连成一棵树;B类点也想用m-1条边连成一棵树(边不可弯曲)。但这些边都不能在非AB类点出相交。如果成功连边则过关。
sl有个不好的习惯:如果没有过关,他就会气得砸键盘。如果在平时,没有什么关系(因为sl不喜欢运动,只喜欢打游戏,以他的力气砸不坏键盘);然而此时yz在他旁边,他一砸键盘,yz就知道他在打游戏了,一定会狠狠地D他一顿。凭sl那点可怜的智商,当然过不了关啦,所以为了拯救sl,你只好教他玩了。
Solution
题意即:在平面上给出两类点,没有三点共线,用两棵不相交的树分别将两类点连通,树边不能相交。
题解给出了一种十分巧妙的构造法:设
接下来就是如何划分出一个个三角形。我们可以对原点集求一次凸包,此时有几种情况:
- 凸包上的某一类点不连续(沿一个时针方向),那么肯定无解。
- 凸包上全是一类点:那么肯定可以在内部找到一个另类点,与凸包上的点构成许多三角形,同时满足
f 的性质。 - 凸包上有两类点,每类点连续。那么我们也可以构成许多三角形,满足
f 的性质。
Code
#include<cstdio>#include<cstdlib>#include<cstring>#include<algorithm>#define fo(i,j,k) for(int i=j;i<=k;++i)#define fd(i,j,k) for(int i=j;i>=k;--i)#define N 3010#define ll long longusing namespace std;struct node{ int x,y,fr,wz;}a[N],an[2][N];int pos,su=0;int n,m;bool vis[N],in[N][N];int num[2],f[N];ll abss(ll x){ return x<0?-x:x;}ll cross(int i,int j,int o){ int X1=a[i].x-a[o].x,Y1=a[i].y-a[o].y,X2=a[j].x-a[o].x,Y2=a[j].y-a[o].y; return (ll)X1*Y2-(ll)X2*Y1;}ll area(int i,int j,int o){ return abss(cross(i,j,o));}bool cmp(node x,node y){ int X1=x.x-a[1].x,Y1=x.y-a[1].y,X2=y.x-a[1].x,Y2=y.y-a[1].y; return ((ll)X1*Y2-(ll)X2*Y1)>0;}int st[N],top=0;int d[N];void get(int u,int v,int w){ d[0]=0; fo(i,1,n) if(!vis[i] && area(u,v,i)+area(u,w,i)+area(v,w,i)==area(u,v,w)) d[++d[0]]=i;}void put(int u,int v){ int co=a[u].fr; if(in[u][v]) return; su++; in[u][v]=in[v][u]=1; an[co][++num[co]].x=a[u].wz,an[co][num[co]].y=a[v].wz;}void work(int u,int v,int w){ get(u,v,w); int p=0; fo(i,1,d[0]) if(a[d[i]].fr==a[w].fr) {p=d[i];break;} if(!p){ put(u,v); fo(i,1,d[0]) if(a[d[i]].fr==a[u].fr) put(d[i],u); return; } vis[p]=true; work(u,v,p),work(p,w,u),work(p,w,v);}int main(){ scanf("%d %d",&n,&m); fo(i,1,n) scanf("%d %d",&a[i].x,&a[i].y),a[i].wz=i; fo(i,1,m) scanf("%d %d",&a[i+n].x,&a[i+n].y),a[i+n].fr=1,a[i+n].wz=i; pos=1; n+=m; fo(i,2,n) if(a[i].y<a[pos].y) pos=i; fo(i,1,n) f[i]=i; swap(a[pos],a[1]); sort(a+2,a+n+1,cmp); st[++top]=1,st[++top]=2; fo(i,3,n){ while(top>1 && cross(i,st[top],st[top-1])>0) top--; st[++top]=i; } bool tp=0; fo(i,1,top){ vis[st[i]]=1; if(i>1 && a[st[i]].fr!=a[st[i-1]].fr) tp=1; } if(!tp){ int pt=0; fo(i,1,n) if(!vis[i] && a[i].fr!=a[st[1]].fr) {pt=i;break;} vis[pt]=1; fo(i,2,top) work(st[i],st[i-1],pt); in[st[1]][st[top]]=1,work(st[1],st[top],pt); fo(i,1,num[0]) printf("%d %d\n",an[0][i].x,an[0][i].y); fo(i,1,num[1]) printf("%d %d\n",an[1][i].x,an[1][i].y); return 0; } int col=a[st[1]].fr; while(a[st[1]].fr==col) fo(i,2,top) swap(st[i],st[i-1]); int np=1,nq; fo(i,2,top) if(a[st[i]].fr!=a[st[1]].fr) break; else np=i; fo(i,np+2,top) if(a[st[i]].fr!=a[st[np+1]].fr){ printf("GG!"); return 0; } nq=top-np; fo(i,2,np) work(st[i-1],st[i],st[np+1]); fo(i,np+2,top) work(st[i-1],st[i],st[1]); fo(i,1,num[0]) printf("%d %d\n",an[0][i].x,an[0][i].y); fo(i,1,num[1]) printf("%d %d\n",an[1][i].x,an[1][i].y); printf("%d\n",su);}
阅读全文
1 0
- 【JZOJ5482】第三题
- 第三章第三题
- 第三章第三题
- 第三章第三题
- 第三题
- 第三题
- 第三题
- 第三题
- 第三题
- 第三题
- 第三题
- 第三题
- 第三题
- 第三题
- 第三题
- 第三题
- 第三题
- 第三题
- 关于GIS的思考
- bzoj3223 Tyvj 1729 文艺平衡树 (splay)
- Git commit消息中附带jira_id/issue_id
- Hibernate的悲观锁和乐观锁(1)
- 【Scikit-Learn 中文文档】模型评估: 量化预测的质量
- 【JZOJ5482】第三题
- 载入内存,让程序运行起来
- 异常处理
- 单例模式分析
- 自顶向下,逐步求精
- 初级程序员(部分)
- 李白打酒
- C++常用操作总结
- layui表单验证demo