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 }

 

posted @ 2018-06-07 17:30  ww3113306  阅读(142)  评论(0编辑  收藏  举报
知识共享许可协议
本作品采用知识共享署名-非商业性使用-禁止演绎 3.0 未本地化版本许可协议进行许可。