1035: [ZJOI2008]Risk
Time Limit: 10 Sec Memory Limit:
162 MB
Submit: 64 Solved: 19
[Submit][Status][Discuss]
Description
经过连续若干年的推广,Risk这个游戏已经风靡全国,成为大众喜闻乐见的重要娱乐方式。Risk这个游戏可以理解为一种简易的策略游戏,游戏者的目的是占领所有的土地。由于游戏规则的规定,只要两个国家相邻,就认为两个国家有交战的可能性。我们现在希望知道在当前的局面下,哪些国家之间有交战的可能性。注意,我们认为只有当两个国家的国界线有公共边的时候才认为相邻,若两个国家的领土只有公共点,则认为两个国家不相邻。每一个国家的边界由一系列线段组成,保证这个边界是一个简单多边形,即严格不自交。为了定位每个国家的位置,我们还给出每个国家最庞大的一支军队的位置,保证这个位置一定出现在某一个形内,而不是出现在某条边界上。
Input
输入文件的第一行中包括两个整数n,m。分别表示地图上的国家数和描述国家的边界的线段的数量。1<=n<=600,1<=m<=4000。接下来n行,每行用一对数描述了某个国家的主力军队的坐标。接下来m行,每行有4个数x1,y1,x2,y2,(x1,y1)-(x2,y2)描述了一条国界线。所有点的坐标都是0-10000之间的整数。保证输入的所有线段至多只会在线段交点处相交。整张地图上有且仅有一块面积无限的空白区域不属于任何国家。每一条国界线两侧的区域或者隶属于两个不同的国家,或者分隔了一个国家与那块无穷大的空白区域。即保证一条国界线两侧的区域不同时属于同一个国家或是同时都是空白区域。所有封闭区域内部包含且仅包含一支主力军队,表示了该区域的归属。例如上图中第一行的数据是合法的。而第二行中的数据都是不合法的。左边的那幅图包含线段两侧都是空白区域;中间的图包含线段两侧区域同时属于同一个国家;右边的图中军队被布置在了国界线上,因此非法;此外若最右侧的图中若没有军队也是非法的。保证输入文件提供的数据都是合法的,你的程序不需要进行数据合法性的判定。
Output
包括n行,每行第一个数字x表示有x个国家可能与这个国家交战,接着在同一行中升序输出x个整数,表示可能与这个国家交战的国家的编号。国家按输入中给出的顺序从1到n编号。注意数字间严格以一个空格隔开,并且不要在行末输出多余的空白字符。
Sample Input
4 12
3 2
11 8
12 17
1 19
0 0 10 0
10 0 20 0
20 0 20 10
20 10 20 20
20 20 10 20
10 20 0 20
0 20 0 10
0 10 0 0
10 0 10 10
0 10 10 10
20 10 10 10
10 20 10 10
3 2
11 8
12 17
1 19
0 0 10 0
10 0 20 0
20 0 20 10
20 10 20 20
20 20 10 20
10 20 0 20
0 20 0 10
0 10 0 0
10 0 10 10
0 10 10 10
20 10 10 10
10 20 10 10
Sample Output
2 2 4
2 1 3
2 2 4
2 1 3
计算几何题真是做的我翔都出来了
首先需要求出来所有的最小封闭图形
将一条边先拆成两条有向边,从每条边出发,沿跟他顺时针夹角最小的边走,走回原边就是一个封闭图形
这样可以求出来许多封闭图形……
虽然最小的封闭图形都求出来了,但是还有一些是外轮廓(就是说如果是两个最小封闭图形相交的边,正向边和反向边都在最小封闭图形中,但有一些边不在最小封闭图形中,这种边只有一条有向边在最小封闭图形中,其他的有向边构成了一个外轮廓)
如何排除这些外轮廓呢……我采取了用叉积算有向面积,可以发现这种外轮廓的有向面积和最小封闭图形的有向面积正负性相反(具体哪个正哪个负由写法决定)
这样我们就求出来了所有最小封闭图形
然后可以求出来那n个点被哪些图形包含(因为图形可能包含图形,所以不一定只被一个最小封闭图形包含)
判包含就随意从这点引一条射线(不能经过多边形端点,这道题多边形端点都是整数,很好搞定),如果跟某个多边形相交的边有奇数条,那么该点被该多边形包含
这样可以求出来每个封闭图形包含哪些点,这样便可以通过一个类似拓扑排序的方法求出来每个封闭图形是哪个国家了
相邻的话有两种情况
有公共边,这个看一下多边形每条边的反向边就好了
包含……这个枚举一个军队……然后将包含这个军队的图形按包含的点数排序,如果相邻两个点数较少的那个存在边反向边不属于任何图形,那么这两个图形相邻
大致就是这样……很麻烦,愿君武运昌盛
#include <cstdio> #include <iostream> #include <algorithm> #include <cmath> #include <cstring> #include <cstdlib> using namespace std; double pi,eps,z; int tot,n,m,i,j,k,o,all,coun[601],xl[8001],x[601],y[601],x1[8001],y11[8001],x2[8001],y2[8001],dl[8001],belong[8001]; int incl[601][601],w[601],p[601],linkk[601][601],who[601],oo[601][601],ans[601][601]; bool ok[601]; bool wwwww (int a,int b) { return p[a]>p[b]; } bool cmp (int a,int b) { return x1[a]*10000+y11[a]<x1[b]*10000+y11[b]; } int anti (int x) { if (x>m) return x-m; else return x+m; } bool meet (double x1,double y11,double x2,double y2,double q1,double p1,double q2,double p2) { if (((fabs(x1-q1)<=eps)&(fabs(y11-p1)<=eps))||((fabs(x1-q2)<=eps)&(fabs(y11-p2)<=eps))) return false; if (fabs(q1-q2)<=eps) if (((fabs(x1-q1)<=eps)&(p1<=y11)&(y11<=p2))|| ((fabs(x2-q1)<=eps)&(p1<=y2)&(y2<=p2))) return true; else return false; double k1,b1,k2,b2,x,y; k1=(y2-y11)/(x2-x1); b1=y11-k1*x1; k2=(p2-p1)/(q2-q1); b2=p1-k2*q1; x=(b2-b1)/(k1-k2); y=x*k1+b1; if (q1>q2) swap(q1,q2); return ((x1<=x)&(x<=x2)&(q1<=x)&(x<=q2)); } double calc (double x1,double y11,double x2,double y2) { double x,y; x=x2-x1; y=y2-y11; if (x==0) if (y>0) return pi/2; else return pi+pi/2; if (y==0) if (x<0) return 0; else return pi; if ((x<0)&(y>0)) return asin(y/(x*x+y*y)); if ((x>0)&(y>0)) return pi-asin(y/(x*x+y*y)); if ((x>0)&(y<0)) return acos(x/(x*x+y*y))+pi; if ((x<0)&(y<0)) return 2*pi-acos(-x/(x*x+y*y)); } double quick (int a,int b) { double x,y,o; x=calc(x2[a],y2[a],x1[a],y11[a]); y=calc(x1[b],y11[b],x2[b],y2[b]); if (x>y) return y+2*pi-x; else return y-x; } int main () { eps=1e-7; pi=3.1415926535897932384626433; scanf("%d %d",&n,&m); for (i=1;i<=n;i++) scanf("%d %d",&x[i],&y[i]); for (i=1;i<=m;i++) { scanf("%d %d %d %d",&x1[i],&y11[i],&x2[i],&y2[i]); x1[i+m]=x2[i]; y11[i+m]=y2[i]; x2[i+m]=x1[i]; y2[i+m]=y11[i]; } for (i=1;i<=2*m;i++) dl[i]=i; sort(dl+1,dl+2*m+1,cmp); for (i=1;i<=m*2;i++) if (belong[dl[i]]==0) { k=dl[i]; tot++; belong[k]=tot; all=0; z=0; do { int s,e,mid; s=1; e=m*2; while (s!=e) { mid=(s+e)/2; if (x1[dl[mid]]*10000+y11[dl[mid]]<x2[k]*10000+y2[k]) s=mid+1; else e=mid; } o=0; for (j=s;(j<=2*m)&(x1[dl[j]]==x2[k])&(y11[dl[j]]==y2[k]);j++) if ((x2[dl[j]]!=x1[k])||(y2[dl[j]]!=y11[k])) if ((o==0)||(quick(k,dl[j])<quick(k,o))) o=dl[j]; belong[o]=tot; double u1,v1,u2,v2; u1=x1[k]-x1[dl[i]]; v1=y11[k]-y11[dl[i]]; u2=x2[k]-x1[dl[i]]; v2=y2[k]-y11[dl[i]]; z+=(u1*v2-u2*v1)/2; k=o; all++; xl[all]=k; } while (k!=dl[i]); while ((z<0)&(all>0)) { belong[xl[all]]=-1; all--; } if (z<0) tot--; } for (i=1;i<=n;i++) { memset(coun,0,sizeof(coun)); for (j=1;j<=m*2;j++) if ((belong[j]>0)&(meet(x[i],y[i],x[i]+1,100000,x1[j],y11[j],x2[j],y2[j]))) coun[belong[j]]++; for (j=1;j<=n;j++) if (coun[j]&1==1) { w[j]++; incl[j][i]=1; oo[j][i]=1; linkk[i][j]=1; } } for (i=1;i<=n;i++) p[i]=w[i]; tot=0; for (i=1;i<=n;i++) if (w[i]==1) { tot++; xl[tot]=i; } i=1; while (i<=tot) { for (k=1;k<=n;k++) if (incl[xl[i]][k]==1) break; who[xl[i]]=k; for (j=1;j<=n;j++) if (linkk[k][j]==1) { incl[j][k]=0; w[j]--; if (w[j]==1) { tot++; xl[tot]=j; } } i++; } for (i=1;i<=m*2;i++) if ((belong[i]>0)&(belong[anti(i)]>0)) ans[who[belong[i]]][who[belong[anti(i)]]]=1; for (i=1;i<=n;i++) for (j=1;j<=m*2;j++) if ((belong[j]==i)&(belong[anti(j)]==-1)) { ok[i]=true; break; } for (i=1;i<=n;i++) { tot=0; for (j=1;j<=n;j++) if (oo[j][i]!=0) { tot++; dl[tot]=j; } if (tot>=2) { sort(dl+1,dl+tot+1,wwwww); for (j=2;j<=tot;j++) if (ok[dl[j]]) { ans[who[dl[j]]][who[dl[j-1]]]=1; ans[who[dl[j-1]]][who[dl[j]]]=1; } } } for (i=1;i<=n;i++) { k=0; for (j=1;j<=n;j++) if (ans[i][j]!=0) k++; printf("%d",k); for (j=1;j<=n;j++) if (ans[i][j]!=0) printf(" %d",j); cout << endl; } }