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 }
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 }