题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1269
2-SAT问题:2-satisfiability问题(可满足性问题)也就是有n个布尔变量,给出一些不能同时存在的情况,询问是否存在满足条件的一组boolean变量的解。做法是运用原命题与逆否命题之间的等价以及同时存在的关系建有向图,对于图中的每一个SCC(强连通分量),他们中的所有的变量要么同时存在,要么同时不存在。因为对于强连通分量中的任何两个点之间都有连线,所以不存在选择某个点而不选择另一个的说法。最终我们只要判断是否存在矛盾(该矛盾不是指变量之间的限制,因为变量之间的限制已经在图中进行反映)。
本题给出n对夫妻,还有一个会议,每对夫妻只能有一个出席,有些人不能同时出席,问是否存在一个组合使得有n个人参加会议而且没有任何矛盾。对于(A,B)之间存在矛盾我们可以知道A->B' ,还有他的逆否命题 B->A',所以要建两条边,应用对称性、tarjan+缩点、判断有没有一对夫妻在同一个SCC中便可以解决这个问题。
代码如下:
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef unsigned int ui; 4 typedef long long ll; 5 typedef unsigned long long ull; 6 #define pf printf 7 #define mem(a,b) memset(a,b,sizeof(a)) 8 #define prime1 1e9+7 9 #define prime2 1e9+9 10 #define pi 3.14159265 11 #define lson l,mid,rt<<1 12 #define rson mid+1,r,rt<<1|1 13 #define scand(x) scanf("%llf",&x) 14 #define f(i,a,b) for(int i=a;i<=b;i++) 15 #define scan(a) scanf("%d",&a) 16 #define mp(a,b) make_pair((a),(b)) 17 #define P pair<int,int> 18 #define dbg(args) cout<<#args<<":"<<args<<endl; 19 #define inf 0x3f3f3f3f 20 inline int read(){ 21 int ans=0,w=1; 22 char ch=getchar(); 23 while(!isdigit(ch)){if(ch=='-')w=-1;ch=getchar();} 24 while(isdigit(ch))ans=(ans<<3)+(ans<<1)+ch-'0',ch=getchar(); 25 return ans*w; 26 } 27 const int maxn=2010; 28 #define maxm 100010 29 int n,m,t; 30 int e; 31 int head[maxn],nxt[maxm*2],dfn[maxn],low[maxn],sccno[maxn]; 32 struct node{ 33 int u,v; 34 }p[maxm*2]; 35 void addedge(int u,int v) 36 { 37 p[e].u=u; 38 p[e].v=v; 39 nxt[e]=head[u]; 40 head[u]=e++; 41 } 42 stack<int> sk; 43 int id,cnt; 44 void tarjan(int u)//tarjan缩点 45 { 46 low[u]=dfn[u]=++id; 47 sk.push(u); 48 for(int i=head[u];~i;i=nxt[i]) 49 { 50 int v=p[i].v; 51 if(!dfn[v]) 52 { 53 tarjan(v); 54 low[u]=min(low[u],low[v]); 55 } 56 else if(!sccno[v]) 57 low[u]=min(low[v],low[u]); 58 } 59 if(low[u]==dfn[u]) 60 { 61 ++cnt;//cnt在循环之外标识这个SCC 62 while(1) 63 { 64 int v=sk.top(); 65 sk.pop(); 66 sccno[v]=cnt; 67 if(u==v)break; 68 } 69 } 70 } 71 int main() 72 { 73 //freopen("input.txt","r",stdin); 74 //freopen("output.txt","w",stdout); 75 std::ios::sync_with_stdio(false); 76 while(scanf("%d",&n)!=EOF) 77 { 78 m=read(); 79 int x,y,a,b,num1,num2; 80 e=0; 81 mem(head,-1); 82 mem(nxt,-1); 83 mem(dfn,0); 84 mem(low,0); 85 mem(sccno,0); 86 id=0;cnt=0; 87 while(!sk.empty())sk.pop(); 88 while(m--) 89 { 90 x=read(),y=read(),a=read(),b=read();//由于编号是0-n-1所以可以乘2扩展成2*n长度 91 num1=x*2+a; 92 num2=y*2+b; 93 addedge(num1,num2^1); 94 addedge(num2,num1^1);//通过异或可以索引一对正反变量的另一个 95 } 96 f(i,0,2*n-1) 97 { 98 if(!dfn[i]) 99 tarjan(i); 100 } 101 bool flag=0; 102 f(i,0,n-1) 103 { 104 // cout<<"i:"<<i<<sccno[i*2]<<":"<<sccno[2*i+1]<<endl; 105 if(sccno[2*i]==sccno[2*i+1])//如果有一对夫妻处于同一个SCC 106 { 107 flag=1; 108 } 109 } 110 if(flag)pf("NO "); 111 else pf("YES "); 112 } 113 }