poj3207 Ikki's Story IV - Panda's Trick 2-sat问题
题意:给定一个圈,m条边(给定),边可以通过外面连,也可以通过里面连,
问连完这m条边后,是否可以做到边两两不相交
题解:
将连里面和连外面分别当做一种决策(即每条边都是决策点),
如果有两条边相冲突,即如果这两条边都连里面就会导致不合法,那就
x --- > y' , y --- > x',
额。。。那怎么判断不合法?
注意到被边u ---> v(u < v)割成两半的分别是:
u ~ v,其他,
一条边不经过这条边的充要条件是:两个端点都在这条边的同一侧。
也就是要么都属于u ~ v,要么都属于其他。
x = x * 2,表示连里面
x = x ^ 1,表示连外面
连边的时候记得双向建边,不然是不可能有大于1的强联通分量的(因为对于任意x点只有出边,任意x'点只有入边)
找到一组冲突的就连x --- > y', y --- > x'.
表示x连里面,y就要放外面,反之同理
1 #include<fstream>//文件输入输出 2 using namespace std; 3 #define R register int 4 #define getchar() *o++ 5 #define AC 2200 6 #define ac 4000100 7 char READ[3001000],*o=READ; 8 int n, m, all, tt, cnt; 9 int low[AC], dfn[AC], belong[AC]; 10 int date[ac], Next[ac], Head[AC], tot; 11 int s[AC], top; 12 bool z[AC]; 13 struct node{ 14 int x,y; 15 }way[AC]; 16 17 inline int read() 18 { 19 int x = 0;char c = getchar(); 20 while(c > '9' || c < '0') c = getchar(); 21 while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar(); 22 return x; 23 } 24 25 inline void add(int f,int w) 26 { 27 date[++tot] = w, Next[tot] = Head[f], Head[f] = tot; 28 date[++tot] = f, Next[tot] = Head[w], Head[w] = tot;//反之也成立,所以要加双向边,不然是不可能有几个连一起的 29 // printf("%d ---> %d\n",f,w); 30 } 31 32 inline void upmin(int &a,int b) 33 { 34 if(b < a) a = b; 35 } 36 37 void pre() 38 { 39 n=read(), m=read(), all = n * 2; 40 for(R i=1;i<=m;i++) 41 { 42 way[i].x = read(), way[i].y = read(); 43 if(way[i].x > way[i].y) swap(way[i].x, way[i].y); 44 for(R j=1;j<i;j++)//防止重边 45 { 46 if(way[j].x > way[i].x && way[j].y < way[i].y) continue; 47 if(way[j].x < way[i].x && way[j].y < way[i].x) continue; 48 if(way[j].x > way[i].y && way[j].y > way[i].y) continue; 49 if(way[j].x < way[i].x && way[j].y > way[i].y) continue;//剩下的就都是冲突的 50 add(i * 2, (j * 2) ^ 1); 51 add(j * 2, (i * 2) ^ 1); 52 } 53 } 54 } 55 56 void tarjan(int x) 57 { 58 int now; 59 dfn[x] = low[x] = ++tt; 60 s[++top] = x, z[x] = true; 61 for(R i = Head[x]; i ; i = Next[i]) 62 { 63 now = date[i]; 64 if(!dfn[now]) 65 { 66 tarjan(now); 67 upmin(low[x], low[now]); 68 } 69 else if(z[now]) 70 upmin(low[x], low[now]); 71 } 72 int b = ++cnt; 73 if(dfn[x] == low[x]) 74 { 75 while(now = s[top--]) 76 { 77 belong[now] = b; 78 z[now] = false; 79 if(now == x) break; 80 } 81 } 82 } 83 84 void work() 85 { 86 for(R i = 2; i <= all; i += 2) 87 { 88 if(belong[i] == belong[i ^ 1]) 89 { 90 printf("the evil panda is lying again\n"); 91 return ; 92 } 93 } 94 printf("panda is telling the truth...\n"); 95 } 96 97 int main() 98 { 99 freopen("in.in","r",stdin); 100 fread(READ, 1, 3000000, stdin); 101 pre(); 102 for(R i=1;i<=all;i++) 103 if(!dfn[i]) tarjan(i); 104 work(); 105 fclose(stdin); 106 return 0; 107 }