2-sat
2-SAT算法本身并不难,关键是连边,不过只需要充分理解好边的概念:a->b即选a必选b。
a、b不能同时选:选了a就要选b',选了b就要选a'。
a、b必须同时选:选了a就要选b,选了b就要选a,选了a'就要选b',选了b'就要选a'。
a、b必须选一个:选了a就要选b',选了b就要选a',选了a'就要选b,选了b'就要选a。
a、b至少选一个:选了a' 就要选b,选了b' 就要选a
※a必须选:a'->a。
https://ac.nowcoder.com/acm/contest/327/F
题目描述:处女座进行了一次探险,发现了一批宝藏。如果他获得这批宝藏,那么他一辈子都不需要工作了。但是处女座遇到了一个难题。
宝藏被装在n个宝箱里,宝箱编号为1,2,…,n,只有所有宝箱在某一时间被打开,处女座才能获得宝藏。有m个开关,每个开关控制k个宝箱,如果按下一个开关,那么这k个宝箱的开关状态都会发生改变(从开启变成关闭,从关闭变成开启),处女座想知道他能否获得这批宝藏
题解:2-sat
1 #include<iostream> 2 #include<string> 3 #include<algorithm> 4 #include<cstdio> 5 #include<vector> 6 #include<cstring> 7 using namespace std; 8 typedef long long ll; 9 const int maxn=4e5+5; 10 vector<int>g[maxn]; 11 int a[maxn],dfn[maxn<<1],low[maxn<<1],col[maxn<<1],head[maxn<<1],stk[maxn<<1],tim,tnt,cnt,col0; 12 bool instk[maxn<<1]; 13 struct edge{ 14 int y; 15 int x; 16 int nex; 17 }e[maxn<<1]; 18 void adde(int q,int w){ 19 e[cnt].x=q; 20 e[cnt].y=w; 21 e[cnt].nex=head[q]; 22 head[q]=cnt++; 23 } 24 void tarjan(int u){ 25 dfn[u]=low[u]=++tim; 26 instk[u]=1; 27 stk[++tnt]=u; 28 for(int i=head[u];i!=-1;i=e[i].nex){ 29 int v=e[i].y; 30 if(!dfn[v]){ 31 tarjan(v); 32 low[u]=min(low[u],low[v]); 33 } 34 else if(instk[v]){ 35 low[u]=min(low[u],dfn[v]); 36 } 37 } 38 if(dfn[u]==low[u]){ 39 col0++; 40 int x; 41 do{ 42 x=stk[tnt]; 43 col[x]=col0; 44 instk[x]=0; 45 tnt--; 46 }while(x!=u); 47 } 48 } 49 int main(){ 50 int n,m; 51 scanf("%d%d",&n,&m); 52 memset(head,-1,sizeof(head)); 53 for(int i=1;i<=n;i++)scanf("%d",&a[i]); 54 for(int i=1;i<=m;i++){ 55 int k; 56 scanf("%d",&k); 57 for(int j=0;j<k;j++){ 58 int x; 59 scanf("%d",&x); 60 g[x].push_back(i); 61 } 62 } 63 int f=0; 64 for(int i=1;i<=n;i++){ 65 if(g[i].size()==0){ 66 if(a[i]==1) 67 {f=1;break;} 68 } 69 if(g[i].size()==1){ 70 if(a[i]){ 71 adde(g[i][0]+m,g[i][0]); 72 } 73 else{ 74 adde(g[i][0],g[i][0]+m); 75 } 76 } 77 if(g[i].size()==2){ 78 if(a[i]){ 79 adde(g[i][0],g[i][1]+m); 80 adde(g[i][1],g[i][0]+m); 81 adde(g[i][1]+m,g[i][0]); 82 adde(g[i][0]+m,g[i][1]); 83 } 84 else{ 85 adde(g[i][0],g[i][1]); 86 adde(g[i][1],g[i][0]); 87 adde(g[i][1]+m,g[i][0]+m); 88 adde(g[i][0]+m,g[i][1]+m); 89 } 90 } 91 } 92 for(int i=1;i<=m*2;i++){ 93 if(!dfn[i]){ 94 tarjan(i); 95 } 96 } 97 for(int i=1;i<=m;i++){ 98 if(col[i]==col[i+m]){ 99 f=1; 100 break; 101 } 102 } 103 if(!f)printf("YES\n"); 104 else printf("NO\n"); 105 return 0; 106 }