標籤:blog os 2014 for io 演算法
題意:給定一個有向圖有m條單向邊,判斷是否任意兩點都可達(a能到b或者b能到a或者互相可達),即求
弱聯通分量。
演算法:
先縮點求強連通分量。然後重建立圖,判斷新圖是否是一條單鏈,即不能分叉,如果分叉了就會存在不可達的情況。
怎麼判斷是否是單鏈呢?
就是每次入度為0的點都只有一個,即每次隊列裡只有一個點。
( o(╯□╰)o。。。。。好像已經是第二次用pair記錄原圖的點對,然後存pair的vector忘記清空導致wa來wa去! )
#include<cstdio>#include<iostream>#include<cstring>#include<queue>#include<vector>#define maxn 1010#define maxm 20010using namespace std;struct node{ int to,next;}edge[maxm],edge2[maxm];int head[maxn],cnt,n;int clk,top,s[maxn],scc,dfn[maxn],low[maxn],belong[maxn];bool instack[maxn],vis[maxn];int head2[maxn],cnt2,in[maxn];typedef pair<int,int> PII;vector<PII> xx;queue<int> q;void add(int x,int y){ edge[cnt].to = y; edge[cnt].next = head[x]; head[x] = cnt++;}void add2(int x,int y){ edge2[cnt2].to = y; edge2[cnt2].next = head2[x]; head2[x] = cnt2++;}void dfs(int x){ dfn[x] = low[x] = clk++; s[top++] = x; instack[x] = true; for(int i=head[x];i!=-1;i = edge[i].next) { int u = edge[i].to; if(dfn[u]==-1) { dfs(u); low[x] = min(low[u],low[x]); } else if(instack[u]) { low[x] = min(low[x],dfn[u]); } } if(low[x]==dfn[x]) { int u; scc++; do { u = s[--top]; instack[u]=false; belong[u] = scc; }while(u!=x); }}void tarjan(){ memset(dfn,-1,sizeof(dfn)); memset(instack,0,sizeof(instack)); memset(belong,0,sizeof(belong)); clk = top = scc = 0; for(int i=1;i<=n;i++) { if(dfn[i]==-1) dfs(i); }}bool topo(){ memset(vis,0,sizeof(vis)); int c = 0; while(!q.empty()) q.pop(); for(int i=1;i<=scc;i++) { if(!in[i]) { c++; q.push(i); } } if(c>1) return false; while(!q.empty()) { int u = q.front(); q.pop(); if(vis[u]) continue; vis[u] = true; c = 0; for(int i=head2[u];i!=-1;i=edge2[i].next) { int v = edge2[i].to; in[v]--; if(!in[v]) { q.push(v); c++; } } if(c>1) return false; } return true;}int main(){ int m,a,b,T; scanf("%d",&T); while(T--) { scanf("%d%d",&n,&m); memset(head,-1,sizeof(head)); memset(in,0,sizeof(in)); xx.clear(); cnt = 0; for(int i=1;i<=m;i++) { scanf("%d%d",&a,&b); add(a,b); xx.push_back(make_pair(a,b)); } tarjan(); memset(head2,-1,sizeof(head2)); cnt2 = 0; for(int i=0;i<xx.size();i++) { int u = xx[i].first,v = xx[i].second; if(belong[u]!=belong[v]) { add2(belong[u],belong[v]); in[belong[v]]++; } } if(topo()) printf("Yes\n"); else printf("No\n"); } return 0;}