2SAT中的重要知识 以前学过忘记存了。现在存一发免得再忘了
#include <cstdio> #include <cstring> #include <algorithm> #include <cstdlib> #include <iostream> #include <vector> #include <cmath> #include <map> #include <string> #include <stack> #include <queue> using namespace std; const int MAXN=1e5+10; struct node { int v; int nxt; }; node edge[MAXN];//边数 int head[MAXN]; int n,m; int Stop,Bcnt,Dindex;//栈头,强通块数,时间戳 int DFN[MAXN],LOW[MAXN];//首时间戳,最近回溯点(根) int Stap[MAXN];//答案栈 int instack[MAXN];//是否在栈中 int Belong[MAXN];//这个点属于第几个强连通块(点) int cnt=0; void add_edge(int u,int v) { edge[cnt].v=v; edge[cnt].nxt=head[u]; head[u]=cnt; cnt++; } void tarjan(int i) { int j; DFN[i]=LOW[i]=++Dindex; instack[i]=1; Stap[++Stop]=i; for (int e=head[i]; e!=-1; e=edge[e].nxt) { j=edge[e].v; if (!DFN[j])//儿子没遍历 { tarjan(j);//遍历 if (LOW[j]<LOW[i])//如果儿子已经形成环 LOW[i]=LOW[j];//父亲也要在回溯的时候进入环 } else if (instack[j]&&DFN[j]<LOW[i])//邻接的在栈里,所以是大大 LOW[i]=DFN[j];//把这个点归到大大那 } if (DFN[i]==LOW[i])//这个点的根是自己 { Bcnt++;//多了一个强连通分量 do { j=Stap[Stop--];//退栈 instack[j]=0;//标记 Belong[j]=Bcnt;//标记 } while (j!=i); } } void solve() { int i; Stop=Bcnt=Dindex=0;//栈头,强通块数,时间戳 memset(DFN,0,sizeof(DFN)); for (int i=1; i<=n; i++) if (!DFN[i]) tarjan(i); } int main() { while (scanf ("%d%d",&n,&m)!=EOF) { memset(head,-1,sizeof(head)); while (m--) { int t1,t2; scanf ("%d%d",&t1,&t2); add_edge(t1,t2); } solve(); } return 0; }