题意:已知一个圆上顺时针放着 n 个点,这 n 个点中有m对顶点之间有连线,连线要么在园外要么在圆内,每个点最多连接一条边,问是否存在一种连接情况满足所有的
边都不相交。
分析:将每条边看成两个点 i ,i+m 分别表示边在内部和在外部,
如果两条边i,j的端点存在序号上的交叉,则这两对点之间的连线一个在外部一个在内部
即如果存在 i,则必存在 j+m ,如果存在 j ,则必存在 i+m,
如果存在 i+m,则必存在 j ,如果存在 j+m ,则必存在 i,
建图的时候连的边为
i -> j+m
j -> i+m
i+m -> j
j+m -> i
求出强连通分量并染色,判断是否存在冲突的情况即可。
#include<stdio.h> #include<string.h> #define maxn 1100 #define clr(x)memset(x,0,sizeof(x)) #define min(a,b)(a)<(b)?(a):(b) #define max(a,b)(a)>(b)?(a):(b) struct Edg { int u,v; }e[1100]; struct node { int to,next; }edge[1000000]; int tot; int head[maxn]; void add(int s,int t) { edge[tot].to=t; edge[tot].next=head[s]; head[s]=tot++; } int dfn[maxn]; int low[maxn]; int sta[maxn]; int ins[maxn]; int col[maxn]; int top,sn,ti; void tarjan(int u) { dfn[u]=low[u]=++ti; sta[++top]=u; ins[u]=1; int i,k; for(i=head[u];i;i=edge[i].next) { k=edge[i].to; if(dfn[k]==0) { tarjan(k); low[u]=min(low[u],low[k]); } else if(ins[k]) low[u]=min(low[u],dfn[k]); } if(dfn[u]==low[u]) { sn++; do { k=sta[top--]; ins[k]=0; col[k]=sn; }while(k!=u); } } int main() { int n,m,i,j; while(scanf("%d%d",&n,&m)!=EOF) { for(i=0;i<m;i++) { scanf("%d%d",&e[i].u,&e[i].v); if(e[i].u>e[i].v) { int tmp=e[i].u; e[i].u=e[i].v; e[i].v=tmp; } } tot=1; clr(head); for(i=0;i<m;i++) for(j=i+1;j<m;j++) if(e[i].u<e[j].v&&e[i].u>e[j].u&&e[i].v>e[j].v ||e[i].v>e[j].u&&e[i].v<e[j].v&&e[i].u<e[j].u) { add(i,j+m); add(j,i+m); add(j+m,i); add(i+m,j); } sn=top=ti=0; clr(dfn); clr(low); clr(ins); clr(col); for(i=0;i<2*m;i++) if(dfn[i]==0) tarjan(i); for(i=0;i<m;i++) if(col[i]==col[i+m]) break; if(i==m) printf("panda is telling the truth...\n"); else printf("the evil panda is lying again\n"); } return 0; }