[JSOI2010] 满汉全席

洛谷 P4171 传送门

bzoj1823 传送门

2-SAT裸题。

简单讲一下2-SAT:

首先把题目给出的种种限制转换为一个图。

以这道题来说,每种菜看作是两个点,一个点代表做成汉式,另一个代表做成满式。

然后考虑约束条件:

比如:评委要求A做成汉式,B做成满式。

那么如果A做成满式,B就一定是满式;同理,如果B做成汉式,那A一定是汉式。

所以这么连边:A满-->B满、B汉->A汉。

不同的题连边方法也略有不同。

然后对这个图求一个强连通分量。

显然,如果选择了某个点,那么那个点所在的强连通分量里的所有点都要选择。

对于1<=X<=n:

如果存在某个X,X汉和X满在一个强连通分量里,就无解。

否则有解。

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;
 5 
 6 int k;
 7 int n,m;
 8 int hd[205],to[2005],nx[2005],ec;
 9 
10 int dish(int id,int kd)
11 {
12     return id*2-kd;
13 }
14 
15 void edge(int af,int at)
16 {
17     to[++ec]=at;
18     nx[ec]=hd[af];
19     hd[af]=ec;
20 }
21 
22 int dfn[205],low[205],dc;
23 int in[205],st[205],tp;
24 int gr[205],gsz[205],gc;
25 
26 void tarjan(int p)
27 {
28     dfn[p]=low[p]=++dc;
29     st[++tp]=p;
30     in[p]=1;
31     for(int i=hd[p];i;i=nx[i])
32     {
33         if(!dfn[to[i]])tarjan(to[i]),low[p]=min(low[p],low[to[i]]);
34         else if(in[to[i]])low[p]=min(low[p],dfn[to[i]]);
35     }
36     if(low[p]==dfn[p])
37     {
38         gc++;
39         int np=0;
40         while(np!=p)
41         {
42             np=st[tp--];
43             gr[np]=gc;
44             gsz[gc]++;
45             in[np]=0;
46         }
47     }
48 }
49 
50 void clean()
51 {
52     memset(hd,0,sizeof(hd));
53     memset(dfn,0,sizeof(dfn));
54     memset(low,0,sizeof(low));
55     memset(gsz,0,sizeof(gsz));
56     dc=ec=gc=0;
57 }
58 
59 int main()
60 {
61     scanf("%d",&k);
62     while(k--)
63     {
64         clean();
65         scanf("%d%d",&n,&m);
66         for(int i=1;i<=m;i++)
67         {
68             int id[2]={0,0},kd[2],p;
69             char lim[10];
70             for(int j=0;j<=1;j++)
71             {
72                 scanf("%s",lim+1);
73                 p=1;
74                 kd[j]=(lim[p++]=='m');
75                 while(lim[p]>='0'&&lim[p]<='9')
76                     id[j]=id[j]*10+lim[p++]-'0';
77             }
78             edge(dish(id[0],kd[0]^1),dish(id[1],kd[1]));
79             edge(dish(id[1],kd[1]^1),dish(id[0],kd[0]));
80         }
81         for(int i=1;i<=2*n;i++)
82             if(!dfn[i])tarjan(i);
83         int fl=1;
84         for(int i=1;i<=n;i++)
85         {
86             if(gr[dish(i,0)]==gr[dish(i,1)])
87             {
88                 fl=0;
89                 break;
90             }
91         }
92         if(fl)printf("GOOD
");
93         else printf("BAD
");
94     }
95     return 0;
96 }
原文地址:https://www.cnblogs.com/cervusy/p/9848898.html