影片連結:D35【模板】2-SAT_嗶哩嗶哩_bilibili
D14 強連通分量 Tarjan 演算法 - 董曉 - 部落格園 (cnblogs.com)
P4782 【模板】2-SAT - 洛谷 | 電腦科學教育新生態 (luogu.com.cn)
// 2-SAT+tarjan O(n+m) #include <iostream> #include <cstring> #include <algorithm> using namespace std; const int N=2000005; int n,m; int head[N],to[N],ne[N],idx; int dfn[N],low[N],tim,stk[N],top,scc[N],cnt; void add(int a,int b){ to[++idx]=b,ne[idx]=head[a],head[a]=idx; } void tarjan(int x){ dfn[x]=low[x]=++tim; stk[++top]=x; for(int i=head[x];i;i=ne[i]){ int y=to[i]; if(!dfn[y]){ //若y尚未訪問 tarjan(y); low[x]=min(low[x],low[y]); } else if(!scc[y]) //若y已訪問且未處理 low[x]=min(low[x],dfn[y]); } if(low[x]==dfn[x]){ //若x是SCC的根 ++cnt; for(int y=-1;y!=x;) scc[y=stk[top--]]=cnt; } } int main(){ scanf("%d%d",&n,&m); for(int i,a,j,b;m--;){ scanf("%d%d%d%d",&i,&a,&j,&b); add(i+!a*n,j+b*n); //xi拆成i和i+n add(j+!b*n,i+a*n); } for(int i=1;i<=2*n;i++) if(!dfn[i]) tarjan(i); //求SCC for(int i=1;i<=n;i++) if(scc[i]==scc[i+n]){ puts("IMPOSSIBLE"); return 0; } puts("POSSIBLE"); for(int i=1;i<=n;i++) printf("%d ",scc[i]>scc[i+n]); }
// 2-SAT+tarjan O(n+m) #include <iostream> #include <cstring> #include <algorithm> using namespace std; const int N=2000005; int n,m; int head[N],to[N],ne[N],idx; int dfn[N],low[N],tim,stk[N],top,scc[N],cnt; void add(int a,int b){ to[++idx]=b,ne[idx]=head[a],head[a]=idx; } void tarjan(int x){ dfn[x]=low[x]=++tim; stk[++top]=x; for(int i=head[x];i;i=ne[i]){ int y=to[i]; if(!dfn[y]){ //若y尚未訪問 tarjan(y); low[x]=min(low[x],low[y]); } else if(!scc[y]) //若y已訪問且未處理 low[x]=min(low[x],dfn[y]); } if(low[x]==dfn[x]){ //若x是SCC的根 ++cnt; for(int y=-1;y!=x;) scc[y=stk[top--]]=cnt; } } int main(){ scanf("%d%d",&n,&m); for(int i,a,j,b;m--;){ scanf("%d%d%d%d",&i,&a,&j,&b); i--,j--; add(2*i+!a,2*j+b); //xi拆成2i和2i+1 add(2*j+!b,2*i+a); } for(int i=0;i<2*n;i++) if(!dfn[i]) tarjan(i); //求SCC for(int i=0;i<2*n;i+=2) if(scc[i]==scc[i+1]){ puts("IMPOSSIBLE"); return 0; } puts("POSSIBLE"); for(int i=0;i<2*n;i+=2) printf("%d ",scc[i]>scc[i+1]); }
板子題:P4171 [JSOI2010] 滿漢全席 - 洛谷 | 電腦科學教育新生態 (luogu.com.cn)
#include <iostream> #include <cstring> #include <algorithm> using namespace std; const int N=205; int t,n,m; int head[N],idx; struct Edge{int to,ne;}e[4005]; int dfn[N],low[N],tim,stk[N],top,scc[N],cnt; char s1[5],s2[5]; void add(int a,int b){ e[++idx].to=b; e[idx].ne=head[a]; head[a]=idx; } void tarjan(int x){ dfn[x]=low[x]=++tim; stk[++top]=x; for(int i=head[x];i;i=e[i].ne){ int y=e[i].to; if(!dfn[y]){ //若y尚未訪問 tarjan(y); low[x]=min(low[x],low[y]); } else if(!scc[y]) //若y已訪問且未處理 low[x]=min(low[x],dfn[y]); } if(low[x]==dfn[x]){ //若x是SCC的根 ++cnt; for(int y=-1;y!=x;) scc[y=stk[top--]]=cnt; } } int main(){ scanf("%d",&t); while(t--){ idx=tim=cnt=top=0; memset(head,0,sizeof head); memset(dfn,0,sizeof dfn); memset(scc,0,sizeof scc); scanf("%d%d",&n,&m); while(m--){ scanf("%s%s",&s1,&s2); int i=0,j=0,a,b,k; a=(s1[0]=='m'?0:1); b=(s2[0]=='m'?0:1); for(k=1;s1[k]>='0'&&s1[k]<='9';) i=i*10+s1[k++]-'0'; for(k=1;s2[k]>='0'&&s2[k]<='9';) j=j*10+s2[k++]-'0'; add(i+n*!a,j+n*b); add(j+n*!b,i+n*a); } for(int i=1;i<=n<<1;++i)if(!dfn[i])tarjan(i); bool flag=0; for(int i=1;i<=n;++i) if(scc[i]==scc[i+n]){ flag=1; break; } flag?puts("BAD"):puts("GOOD"); } }
練習題:
Catowice City - 洛谷 | 電腦科學教育新生態 (luogu.com.cn)
P3007 [USACO11JAN] The Continental Cowngress G - 洛谷 | 電腦科學教育新生態 (luogu.com.cn)
Ring Road 2 - 洛谷 | 電腦科學教育新生態 (luogu.com.cn)