【判定弱连通】==【tarjan求scc + 缩点+拓扑】
2017-05-27 22:00
411 查看
给你一个N个点M条边的有向图,判断该图是否为弱连通。
思路:首先tarjan求SCC + 缩点,建成新图后,可以证明的是,新图必定有入度为0的点。在保证每个点都有边相连的前提下,我们进行一次拓扑排序,在这个过程中若遇到不符合弱连通的条件即跳出。反之一直处理到队列为空,这时说明该图为弱连通图。
遵循条件
一:新图不能有多于1个的入度为0的点,这是保证每个点都有边相连。
二:在拓扑排序遍历点u的过程中,若去掉与u相关的边后出现多于1个的入度为0的点,说明这些点只能由u到达,而它们之间不存在可达路径。这时不满足弱连通,跳出。
(其实就是 缩点后的新图,一定要有一个 确切的序列 —这样才说明图是一个弱连通)
代码
思路:首先tarjan求SCC + 缩点,建成新图后,可以证明的是,新图必定有入度为0的点。在保证每个点都有边相连的前提下,我们进行一次拓扑排序,在这个过程中若遇到不符合弱连通的条件即跳出。反之一直处理到队列为空,这时说明该图为弱连通图。
遵循条件
一:新图不能有多于1个的入度为0的点,这是保证每个点都有边相连。
二:在拓扑排序遍历点u的过程中,若去掉与u相关的边后出现多于1个的入度为0的点,说明这些点只能由u到达,而它们之间不存在可达路径。这时不满足弱连通,跳出。
(其实就是 缩点后的新图,一定要有一个 确切的序列 —这样才说明图是一个弱连通)
代码
#include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #include<stack> #include<queue> #include<iostream> #include<vector> using namespace std; const int MAXN= 10010+10; struct Edge { int from,to,next; }edge[60000+10]; int head[MAXN],top; int n,m; void init(){ memset(head,-1 4000 ,sizeof(head)); top=0; } void addedge(int a,int b){ Edge e={a,b,head[a]}; edge[top]=e;head[a]=top++; } void getmap(){ int a,b; while(m--){ scanf("%d%d",&a,&b); addedge(a,b); } } int low[MAXN],dfn[MAXN]; int scc_cnt,sccno[MAXN]; stack<int>S;int Instack[MAXN]; vector<int>G[MAXN]; int dfs_clock; void tarjan(int now,int par){ low[now]=dfn[now]=++dfs_clock; S.push(now);Instack[now]=1; for(int i=head[now];i!=-1;i=edge[i].next){ Edge e=edge[i]; if(!dfn[e.to]){ tarjan(e.to,now); low[now]=min(low[now],low[e.to]); }else if(Instack[e.to]) low[now]=min(low[now],dfn[e.to]); } if(low[now]==dfn[now]) { scc_cnt++; for(;;){ int nexts=S.top();S.pop();Instack[nexts]=0; sccno[nexts]=scc_cnt; if(nexts==now) break; } } } void find_cut(int le,int ri){ memset(low,0,sizeof(low)); memset(dfn,0,sizeof(dfn)); memset(Instack,0,sizeof(Instack)); memset(sccno,0,sizeof(sccno)); dfs_clock=scc_cnt=0; for(int i=le;i<=ri;i++){ if(!dfn[i]) tarjan(i,-1); } } int in[MAXN]; void suodian(){ for(int i=1;i<=scc_cnt;i++) { in[i]=0;G[i].clear(); } for(int i=0;i<top;i++){ Edge e=edge[i]; int now=sccno[e.from]; int nexts=sccno[e.to]; if(now!=nexts){ G[now].push_back(nexts); in[nexts]++; } } } queue<int>Q; bool topo(){ while(!Q.empty()) Q.pop(); int num=0; for(int i=1;i<=scc_cnt;i++){ if(!in[i]) { Q.push(i); num++; if(num>1) return false; } } int k=0; while(!Q.empty()){ int now=Q.front();Q.pop();num=0;k++; for(int i=0;i<G[now].size();i++){ int v=G[now][i]; if(--in[v]==0){ Q.push(v); num++; if(num>1) return false; } } } return k==scc_cnt; // 可能缩点后的新图本身就不是连通的 } void solve(){ find_cut(1,n); suodian(); if(scc_cnt==1) puts("Yes"); else puts(topo()?"Yes":"No"); } int main(){ int t;cin>>t;while(t--){ cin>>n>>m; init(); getmap(); solve(); } return 0; }
相关文章推荐
- poj 2762 Going from u to v or from v to u? 【判断图是否为弱连通】 【tarjan求SCC + 缩点 + 拓扑排序】
- Going from u to v or from v to u? 【判定弱连通】=【tarjan求scc+ 缩点+topo】
- hdoj 1827 Summer Holiday 【有向图 连通最少的点来间接连通所有点】 【tarjan求 SCC + 缩点】
- [BZOJ 1093 && YZOI1172] Tarjan缩点+拓扑DP 最大半连通子图
- Kosaraju算法求有向强连通分量,缩点后是DAG的拓扑序列(从小到大)
- POJ 1236 Network of Schools(Tarjan Algorithm求强连通子集,缩点后DAG上出或入度为0的点)
- Tarjan求强连通(缩点)
- 强连通分量及缩点tarjan算法解析
- 强连通分量,Tarjan,缩点(Network of Schools,POJ 1236)
- Network of Schools POJ - 1236 tarjan强连通分量缩点
- hdoj 3836 Equivalent Sets 【tarjan 求SCC + 缩点】
- BZOJ 1924 [Sdoi2010]所驼门王的宝藏 tarjan缩点+拓扑DP
- BZOJ 1512 [POI2006]Pro-Professor Szu Tarjan缩点+拓扑DP
- POJ 1236 Network Of Schools ( tarjan求强连通分量 + 缩点成DAG图 )
- HDU1827 Summer Holiday 强连通 Tarjan 缩点 统计
- UOJGraph(tarjan缩点+拓扑)
- 51nod 1456 小K的技术(Tarjan强连通分量缩点,并查集)
- BZOJ1565 [NOI2009]植物大战僵尸 【最大权闭合子图 + tarjan缩点(或拓扑)】
- POJ 3114 Countries in War 强连通tarjan缩点后 跑最短路spfa
- BZOJ 1093 最大半连通子图(tarjan缩点 拓扑排序)