[JSOI2010]满汉全席 2-sat

做的第一道2-Sat的题emmm。。。

由题意可知,每个评委的两个要求中,至少要满足一个,

因此,如果有一个不满足,那另一个必定要满足

所以对于每道菜我们拆两个点,一个是满族口味,一个是汉族口味,

如果我们要不满足满族口味,也就意味着我们要做汉族口味

所以照着每位评委的菜连边即可

比如说一个评委要求m1,m2,

那么不做m1就意味着做h1,所以h1 --- > m2

同理,h2 --- > m1

然后判断一个菜的满族做法和汉族做法是不是在同一个强连通分量里,

因为一个菜不可能同时做两种做法,所以如果在同一个强连通分量里的话,就是不合法的

连边应该还有更方便的写法,只不过我懒得想就手动模拟了

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 #define R register int
  4 #define AC 450
  5 #define ac 4500
  6 #define D printf("line in %d\n",__LINE__);
  7 int T, n, m;
  8 int dfn[AC], low[AC],belong[AC],cnt;
  9 int date[ac], Next[ac], Head[AC], tot;
 10 int q[AC], top, timer;
 11 char c1[5], c2[5];
 12 bool z[AC];
 13 
 14 inline void add(int f, int w)
 15 {
 16 //  printf("%d --- > %d\n",f,w);
 17     date[++tot] = w, Next[tot] = Head[f], Head[f] = tot;
 18 }
 19 
 20 inline void upmin(int &a, int b)
 21 {
 22     if(b < a) a = b;
 23 }
 24 //拆成4个点,i --- > 选汉式,i+n --- >选满式 
 25 void pre()
 26 {
 27     R x1, x2;
 28     scanf("%d%d",&n, &m);
 29     for(R i = 1; i <= m; i ++)
 30     {
 31         scanf("%s%s", c1 + 1, c2 + 1);
 32         x1 = x2 = 0;
 33         int l = 2;
 34         while(c1[l] <= '9' && c1[l] >= '0') x1 = x1 * 10 + c1[l] - '0', ++ l;
 35         l=2;
 36         while(c2[l] <= '9' && c2[l] >= '0') x2 = x2 * 10 + c2[l] - '0', ++ l;//得到菜的编号
 37         if(c1[1] == 'm') //不满足x1,满足x2,此时x1是'm',所以不加
 38         {
 39             if(c2[1] == 'm') add(x1, x2 + n);//x1不做满式(做汉式) --- > x2 做满式
 40             else add(x1, x2);//x1做汉式,x2做汉式
 41         }
 42         else//不满足x1,满足x2,此时x1是h,所以加
 43         {
 44             if(c2[1] == 'm') add(x1 + n, x2 + n);//如果x2是m的话
 45             else add(x1 + n, x2);//是h的话error!!!别打错了啊!!!是不满足x1啊
 46         }
 47         if(c2[1] == 'm') //满足x1,不满足x2,此时x2是'm',所以不加
 48         {
 49             if(c1[1] == 'm') add(x2, x1 + n);//此时x1是m,所以加
 50             else add(x2, x1);//此时x1是h,所以不加
 51         }
 52         else//满足x1,不满足x2,此时x2是h,所以加
 53         {
 54             if(c1[1] == 'm') add(x2 + n, x1 + n);//此时x1是m,所以加
 55             else add(x2 + n, x1);//x1是h,所以不加
 56         }
 57     }   
 58 }
 59 
 60 void tarjan(int x)
 61 {
 62     R now;
 63     dfn[x] = low[x] = ++timer;
 64     q[++top] = x, z[x] = true;
 65     for(R i = Head[x]; i; i = Next[i])
 66     {
 67         now = date[i];
 68         if(!dfn[now])
 69         {
 70             tarjan(now);
 71             upmin(low[x], low[now]);
 72         }
 73         else if(z[now]) upmin(low[x], low[now]);
 74     }
 75     if(dfn[x] == low[x])
 76     {
 77         z[x] = false, ++cnt, now = 0;
 78         while(now != x)//因为回到这里的时候已经操作完了
 79         {
 80             now = q[top--];
 81             z[now] = false, belong[now] = cnt;
 82         }
 83     }//--放后面可以保证top不被忽略
 84 }
 85 
 86 void work()
 87 {
 88     bool flag;
 89     scanf("%d", &T);
 90     while(T --)
 91     {
 92         flag = false;
 93         memset(Head, 0, sizeof(Head));
 94         memset(dfn, 0, sizeof(dfn));//因为是用dfn判断有无访问的,所以memset dfn就可以了
 95         memset(z, 0, sizeof(z));
 96         tot = timer = cnt = 0;
 97         pre();
 98         int all = 4 * n;
 99         for(R i = 1; i <= all; i ++)
100             if(!dfn[i]) tarjan(i);
101         for(R i = 1; i <= n; i ++)//不能既选h又选m 
102             if(belong[i] == belong[n + i]){flag = 1; break;}
103         //for(R i=1;i<=2*n;i++) printf("%d ",belong[i]);
104         if(!flag) printf("GOOD\n");
105         else printf("BAD\n");
106     }
107 }
108 
109 int main()
110 {
111 //  freopen("in.in","r",stdin);
112     work();
113 //  fclose(stdin);
114     return 0;
115 }
View Code

 

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