题意:
一个圆,圆的边上按顺时针放着n个点。现在要连m条边,比如a,b,那么a到b可以从圆的内部连接,也可以从圆的外部连接。给你的信息中,每个点最多只会连接的一条边。问能不能连接这m条边,使这些边都不相交。
思路:
把每条边都抽象成一个点a,再把a点拆成两个点(2-SAT嘛),分别为a0和a1,分别表示这条边从内部连何从外部连,说到这里应该会建图了吧!
再提示一下,对于有可能交叉的两条边考虑连边。怎么判断有可能交叉大家都会吧,细心点就是了!
View Code
1 #include <cstdio> 2 #include <cstdlib> 3 #include <cstring> 4 #include <iostream> 5 #define N 30000 6 #define M 1500000 7 using namespace std; 8 int head[N],next[M],to[M],belong[N],dfn[N],low[N],n,m,t,p,divg,cnt,a[M],b[M],stack[N]; 9 bool fg[N]; 10 void read() 11 { 12 memset(head,-1,sizeof head);cnt=0; 13 memset(belong,0,sizeof belong); 14 memset(dfn,0,sizeof dfn); 15 memset(fg,0,sizeof fg); 16 t=0; p=0; divg=0; 17 for(int i=1;i<=m;i++) 18 { 19 scanf("%d%d",&a[i],&b[i]); 20 if(a[i]>b[i]) swap(a[i],b[i]); 21 } 22 } 23 inline void add(int u,int v) 24 { 25 to[cnt]=v; next[cnt]=head[u]; head[u]=cnt++; 26 } 27 bool judge(int x,int y) 28 { 29 if(a[x]>a[y]&&a[x]<b[y]&&b[x]>b[y]) return true; 30 if(a[y]>a[x]&&a[y]<b[x]&&b[y]>b[x]) return true; 31 return false; 32 } 33 void create() 34 { 35 for(int i=1;i<=m;i++) 36 for(int j=i+1;j<=m;j++) 37 if(judge(i,j)) 38 add(i+m,j),add(j,i+m),add(i,j+m),add(j+m,i); 39 } 40 void dfs(int u) 41 { 42 t++; 43 dfn[u]=low[u]=t; 44 stack[++p]=u; fg[u]=true; 45 for(int i=head[u];~i;i=next[i]) 46 { 47 if(!dfn[to[i]]) 48 { 49 dfs(to[i]); 50 low[u]=min(low[u],low[to[i]]); 51 } 52 else if(fg[to[i]]) low[u]=min(low[u],dfn[to[i]]); 53 } 54 if(dfn[u]==low[u]) 55 { 56 divg++; 57 int tmp=-1; 58 while(tmp!=u) 59 { 60 tmp=stack[p--]; 61 belong[tmp]=divg; 62 fg[tmp]=false; 63 } 64 } 65 } 66 bool check() 67 { 68 for(int i=1;i<=m;i++) 69 if(belong[i]==belong[i+m]) return false; 70 return true; 71 } 72 void tarjan() 73 { 74 for(int i=1;i<=m+m;i++) 75 if(!dfn[i]) dfs(i); 76 if(check()) printf("panda is telling the truth...\n"); 77 else printf("the evil panda is lying again\n"); 78 } 79 int main() 80 { 81 while(scanf("%d%d",&n,&m)!=EOF) 82 { 83 read(); 84 create(); 85 tarjan(); 86 } 87 return 0; 88 }