tarjan
学习资料:https://www.cnblogs.com/shadowland/p/5872257.html
板子:
void tarjan(int u){ dfn[u]=low[u]=++cnt; sta[++top]=u; vis[u]=true; for(int i=0;i<g[u].size();i++){ int v=g[u][i];
if(!dfn[v]){ tarjan(v),low[u]=min(low[u],low[v]); } else if(vis[v]) low[u]=min(low[u],dfn[v]); } if(dfn[u]==low[u]){ cmp[u]=++tot; vis[u]=false; int len=top; while(sta[top]!=u){ cmp[sta[top]]=tot; vis[sta[top--]]=false; } top--; sum[tot]=len-top;//缩点,记录该联通块的大小 } }
例题:poj 2186 http://poj.org/problem?id=2186
#include<iostream> #include<cstring> #include<cstdio> #include<algorithm> #include<vector> using namespace std; const int M=1e4+5; vector<int>g[M]; int out[M],cmp[M],dfn[M],low[M],sta[M],vis[M],sum[M],tot,cnt,top; void tarjan(int u){ dfn[u]=low[u]=++cnt; sta[++top]=u; vis[u]=true; for(int i=0;i<g[u].size();i++){ int v=g[u][i]; if(!dfn[v]){ tarjan(v),low[u]=min(low[u],low[v]); } else if(vis[v]) low[u]=min(low[u],dfn[v]); } if(dfn[u]==low[u]){ cmp[u]=++tot; vis[u]=false; int len=top; while(sta[top]!=u){ cmp[sta[top]]=tot; vis[sta[top--]]=false; } top--; sum[tot]=len-top; } } int main(){ int n,m; scanf("%d%d",&n,&m); while(m--){ int x,y; scanf("%d%d",&x,&y); g[x].push_back(y); } for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i); for(int i=1;i<=n;i++){ for(int j=0;j<g[i].size();j++){ int v=g[i][j]; if(cmp[i]!=cmp[v]) out[cmp[i]]++; } } /*for(int i=1;i<=tot;i++) cout<<out[i]<<" "; cout<<endl;*/ int s=0; for(int i=1;i<=tot;i++){ if(!out[i]){ if(s){ return puts("0"),0; } else s=sum[i]; } } printf("%d\n",s); return 0; }
题目:poj1263
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<vector> using namespace std; const int M=102; bool vis[M]; vector<int>g[M]; int cmp[M],dfn[M],low[M],sta[M],out[M],in[M]; int n,m,cnt,tot,top; inline int read(){ int summ=0,x=1; char ch=getchar(); while(ch<'0'||ch>'9'){ if(ch=='-') x=0; ch=getchar(); } while(ch>='0'&&ch<='9') summ=(summ<<1)+(summ<<3)+(ch^48),ch=getchar(); return x?summ:-summ; } inline void write(int x){ if(x<0) putchar('-'),x=-x; if(x>9) write(x/10); putchar(x%10+'0'); } void init(){ tot=cnt=top=0; for(int i=0;i<=n;i++) g[i].clear(),sta[i]=0,cmp[i]=0,vis[i]=true,dfn[i]=0,in[i]=0,out[i]=0,low[i]=0; } void tarjan(int u){ dfn[u]=low[u]=++cnt; sta[++top]=u; vis[u]=true; for(int i=0;i<g[u].size();i++){ int v=g[u][i]; if(!dfn[v]){ tarjan(v); low[u]=min(low[u],low[v]); } else if(vis[v]) low[u]=min(low[u],dfn[v]); } if(dfn[u]==low[u]){ cmp[u]=++tot; vis[u]=false; while(sta[top]!=u){ cmp[sta[top]]=tot; vis[sta[top--]]=false; } top--; } } int main(){ while(~scanf("%d",&n)){ init(); for(int i=1;i<=n;i++){ int x=read(); while(x){ g[i].push_back(x); x=read(); } } for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i); int countt=0,countt1=0; for(int i=1;i<=n;i++){ for(int j=0;j<g[i].size();j++){ int v=g[i][j]; if(cmp[i]!=cmp[v]) out[cmp[i]]++,in[cmp[v]]++; } } //cout<<countt<<"~~"<<countt1<<endl; for(int i=1;i<=tot;i++){ if(!in[i]){ countt++; } if(!out[i]) countt1++; } write(countt); putchar('\n'); if(tot==1) puts("0"); else write(max(countt1,countt)),putchar('\n'); } return 0; }
题目:hud2767
给定一张有向图,问最少添加几条边使得有向图成为一个强连通图。
Tarjan入门经典题,用tarjan缩点,然后就变成一个有向无环图(DAG)了。
我们要考虑的问题是让它变成强连通,让DAG变成强连通就是把尾和头连起来,也就是入度和出度为0的点。
统计DAG入度和出度,然后计算头尾,最大的那个就是所求。
#include<iostream> #include<cstring> #include<cstdio> #include<algorithm> #include<vector> using namespace std; inline int read(){ int sum=0,x=1; char ch=getchar(); while(ch<'0'||ch>'9'){ if(ch=='-') x=0; ch=getchar(); } while(ch>='0'&&ch<='9') sum=(sum<<1)+(sum<<3)+(ch^48),ch=getchar(); return x?sum:-sum; } inline void write(int x){ if(x<0) putchar('-'),x=-x; if(x>9) write(x/10); putchar(x%10+'0'); } int mi(int x,int y){ return x<y?x:y; } int ma(int x,int y){ return x>y?x:y; } const int M=2e4+4; vector<int>g[M]; int dfn[M],low[M],sta[M],cmp[M],in[M],out[M],n,m,top,tot,cnt; bool vis[M]; void tarjan(int u){ low[u]=dfn[u]=++cnt; sta[++top]=u; vis[u]=true; for(int i=0;i<g[u].size();i++){ int v=g[u][i]; if(!dfn[v]){ tarjan(v); low[u]=mi(low[u],low[v]); } else if(vis[v]) low[u]=mi(low[u],dfn[v]); } if(low[u]==dfn[u]){ cmp[u]=++tot; vis[u]=false; while(sta[top]!=u){ cmp[sta[top]]=tot; vis[sta[top--]]=false; } top--; } } void init(){ tot=top=cnt=0; for(int i=0;i<=n;i++) g[i].clear(),cmp[i]=0,low[i]=0,dfn[i]=0,out[i]=0,in[i]=0; } int main(){ int t=read(); while(t--){ n=read(),m=read(); /*if(m==0){ write(n); putchar('\n'); continue; }*/ init(); while(m--){ int x=read(),y=read(); g[x].push_back(y); } for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i); if(tot==1){ puts("0"); continue; } for(int i=1;i<=n;i++) for(int j=0;j<g[i].size();j++){ int v=g[i][j]; if(cmp[i]!=cmp[v]) out[cmp[i]]++,in[cmp[v]]++; } int ans1=0,ans2=0; //cout<<"~~"<<tot<<endl; for(int i=1;i<=tot;i++){ if(!out[i]) ans1++; if(!in[i]) ans2++; } write(ma(ans1,ans2)); putchar('\n'); } return 0; }
题:poj2762
题意·:给定图,问任意俩点x能否到达y(不需要俩俩可达)
强联通+拓扑排序
在sort过程中若入度为0的点数出现2次及2次以上则“no”
详见:https://www.cnblogs.com/scau20110726/archive/2013/05/23/3094495.html
#include<iostream> #include<cstring> #include<cstdio> #include<algorithm> #include<vector> #include<queue> using namespace std; typedef long long ll; const int M=10005; int in[M],out[M],sta[M],dfn[M],low[M],cmp[M],tot,top,cnt,n,m; bool vis[M]; vector<int>g[M],newg[M]; void tarjan(int u){ low[u]=dfn[u]=++cnt; sta[++top]=u; vis[u]=true; for(int i=0;i<g[u].size();i++){ int v=g[u][i]; if(!dfn[v]){ tarjan(v); low[u]=min(low[u],low[v]); } else if(vis[v]) low[u]=min(low[u],dfn[v]); } if(low[u]==dfn[u]){ cmp[u]=++tot; vis[u]=false; while(sta[top]!=u){ cmp[sta[top]]=tot; vis[sta[top--]]=false; } top--; } } void init(){ tot=top=cnt=0; for(int i=0;i<=n;i++) vis[i]=false,newg[i].clear(),g[i].clear(),sta[i]=0,in[i]=0,out[i]=0,dfn[i]=0,low[i]=0,cmp[i]=0; } void tuopu(){ for(int i=1;i<=n;i++) for(int j=0;j<g[i].size();j++){ int v=g[i][j]; if(cmp[i]!=cmp[v]) out[cmp[i]]++,in[cmp[v]]++,newg[cmp[i]].push_back(cmp[v]); } queue<int>que; int ans=0; //vector<int>ans; while(!que.empty()) que.pop(); for(int i=1;i<=tot;i++) if(!in[i]) que.push(i),ans++; if(ans>1){ puts("No"); return ; } while(!que.empty()){ int u=que.front(); ans=0; que.pop(); //ans.push_back(u); for(int i=0;i<newg[u].size();i++){ int v=newg[u][i]; in[v]--; if(!in[v]){ que.push(v); ans++; } } if(ans>1){ puts("No"); return ; } } //cout<<tot<<endl; puts("Yes"); } int main(){ int t; scanf("%d",&t); while(t--){ scanf("%d%d",&n,&m); init(); while(m--){ int x,y; scanf("%d%d",&x,&y); g[x].push_back(y); } for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i); tuopu(); } return 0; }