bzoj 1823: [JSOI2010]满汉全席 && bzoj 2199 : [Usaco2011 Jan]奶牛议会 2-sat

noip之前学的内容了,看到题竟然忘了怎么建图了,复习一下。

2-sat

大概是对于每个元素,它有0和1两种选择,必须选一个但不能同时选。这之间又有一些二元关系,比如x&y=1等等。。。

先把每个点拆成0和1两个点。

那么我们就建图,如果x等于A的话y必须等于B,那么从x的A点向y的B点连一条有向边,表示选了一个点它所有的后继点也必须选。

没有一组合法解的情况当且仅当x的01两个点缩点后在同一个强联通分量里。

 

bzoj 1823 

裸题

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #define N 205
 6 #define M 4005
 7 using namespace std;
 8 int n,m;
 9 int head[N],ver[M],nxt[M],tot;
10 void add(int a,int b)
11 {
12     tot++;nxt[tot]=head[a];head[a]=tot;ver[tot]=b;return ;
13 }
14 int dfn[N],low[N],tim,in[N],st[N],top,cnt,be[N];
15 void dfs(int x)
16 {
17     dfn[x]=low[x]=++tim;
18     st[++top]=x;
19     in[x]=1;
20     for(int i=head[x];i;i=nxt[i])
21     {
22         if(!dfn[ver[i]])
23         {
24             dfs(ver[i]);
25             low[x]=min(low[x],low[ver[i]]);
26         }
27         else if(in[ver[i]])
28         {
29             low[x]=min(low[x],dfn[ver[i]]);
30         }
31     }
32     if(low[x]==dfn[x])
33     {
34         cnt++;int y;
35         do
36         {
37             y=st[top--];
38             be[y]=cnt;
39             in[y]=0;
40         }while(y!=x);
41     }
42     return ;
43 }
44 int main()
45 {
46     int cas;
47     scanf("%d",&cas);
48     while(cas--)
49     {
50         tim=tot=cnt=top=0;
51         memset(be,0,sizeof(be));
52         memset(head,0,sizeof(head));
53         memset(dfn,0,sizeof(dfn));
54         memset(low,0,sizeof(low));
55         scanf("%d%d",&n,&m);
56         char s1[10],s2[10];
57         for(int i=1;i<=m;i++)
58         {
59             scanf("%s%s",s1,s2);
60             int k1,k2;k1=k2=0;
61             int len1=strlen(s1);
62             for(int i=1;i<len1;i++)
63             {
64                 k1=k1*10+s1[i]-'0';
65             }
66             int len2=strlen(s2);
67             for(int i=1;i<len2;i++)
68             {
69                 k2=k2*10+s2[i]-'0';
70             }
71             int op1,op2;
72             if(s1[0]=='m')op1=1;else op1=0;
73             if(s2[0]=='m')op2=1;else op2=0;
74             add(k1+(op1^1)*n,k2+op2*n);
75             add(k2+(op2^1)*n,k1+op1*n);
76         }
77         for(int i=1;i<=2*n;i++)if(!dfn[i])dfs(i);
78         bool flag=0;
79         for(int i=1;i<=n;i++)if(be[i]==be[i+n])flag=1;
80         if(flag)puts("BAD");
81         else puts("GOOD");
82     }
83     return 0;
84 }
View Code

 

bzoj 2199

按2-sat建完图之后,从每个点开始dfs一遍。

如果一个点能访问到它的对立点说明这个点不能选。

如果x的两个点都不能选说明无解,相当于在同一个强联通分量里。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #define N 2005
 6 #define M 8005
 7 using namespace std;
 8 int n,m;
 9 int head[N],ver[M],nxt[M],tot;
10 void add(int a,int b)
11 {
12     tot++;nxt[tot]=head[a];head[a]=tot;ver[tot]=b;return ;
13 }
14 int ans[N];
15 int v[N];
16 void dfs(int x)
17 {
18     v[x]=1;
19     for(int i=head[x];i;i=nxt[i])
20     {
21         if(!v[ver[i]])dfs(ver[i]);
22     }
23 }
24 int main()
25 {
26     scanf("%d%d",&n,&m);
27     char s1[3],s2[3];
28     int t1,t2;
29     for(int i=1;i<=m;i++)
30     {
31         scanf("%d",&t1);scanf("%s",s1);
32         scanf("%d",&t2);scanf("%s",s2);
33         int op1,op2;
34         if(s1[0]=='Y')op1=1;else op1=0;
35         if(s2[0]=='Y')op2=1;else op2=0;
36         add(t1+(op1^1)*n,t2+op2*n);
37         add(t2+(op2^1)*n,t1+op1*n);
38     }
39     bool flag=0;
40     for(int i=1;i<=n;i++)
41     {
42         int now=0;
43         memset(v,0,sizeof(v));
44         dfs(i);
45         if(v[i+n])now++;
46         memset(v,0,sizeof(v));
47         dfs(i+n);
48         if(v[i])now+=2;
49         ans[i]=now;
50         if(now==3)flag=1;
51     }
52     if(flag)puts("IMPOSSIBLE");
53     else
54     {
55         for(int i=1;i<=n;i++)
56         {
57             if(!ans[i])putchar('?');
58             else if(ans[i]==1)putchar('Y');
59             else putchar('N');
60         }
61     }
62     return 0;
63 }
View Code

 

posted @ 2017-03-24 09:13  SD_le  阅读(187)  评论(0编辑  收藏  举报
重置按钮