给一个有向图,问是否该图上任意两点间可达。
首先容易想到缩点成有向无环图,其次就是如何处理任意两点间可达。
我在纸上画了一些情况:
4 3 1 2 2 3 2 4 4 4 1 2 1 3 2 4 3 4 3 3 1 2 2 3 1 3 7 8 1 2 1 3 3 4 2 4 4 5 4 6 5 7 6 7 5 6 1 2 1 3 2 3 3 4 3 5 4 5 NNYNY
根据这里一直在纠结如何通过入度出度直接判断。但是一直觉得不严谨。。
然后发现只要拓扑序列唯一即可。这样图中就没有 没有关系的点,还是很巧妙的。。
#include<cstdio> #include<cstring> #include<cmath> #include<iostream> #include<algorithm> #include<vector> #include<queue> const int maxn=1010; const int maxm=6010; using namespace std; int h,head[maxn],n,m,in[maxn],out[maxn]; int sta[maxn],top,vis[maxn],dfn[maxn],low[maxn],ccnt,id; vector<int> e[maxn]; vector<int> edge[maxn]; vector<int> part[maxn]; int inpart[maxn]; void tarjan(int x) { int i,j; dfn[x]=low[x]=id++; vis[x]=1; sta[++top]=x; for(i=0;i<e[x].size();i++) { j=e[x][i]; if(dfn[j]==-1) { tarjan(j); low[x]=min(low[x],low[j]); } else if(vis[j]) low[x]=min(low[x],dfn[j]); } if(dfn[x]==low[x]) { do { j=sta[top--]; vis[j]=0; part[ccnt].push_back(j); inpart[j]=ccnt; }while(j!=x); ccnt++; } } void solve() { memset(sta,-1,sizeof sta); memset(vis,0,sizeof vis); memset(dfn,-1,sizeof dfn); memset(low,-1,sizeof low); top=ccnt=id=0; for(int i=1;i<=n;i++) if(dfn[i]==-1) tarjan(i); } int topo() { queue<int> q; for(int i=0;i<ccnt;i++) if(in[i]==0) q.push(i); while(!q.empty()) { if(q.size()>1) return 0; int x=q.front(); q.pop(); for(int i=0;i<edge[x].size();i++) { in[edge[x][i]]--; if(in[edge[x][i]]==0) q.push(edge[x][i]); } } return 1; } int main() { int T,a,b,i,j; scanf("%d",&T); while(T--) { scanf("%d%d",&n,&m); for(i=0;i<=n;i++) { part[i].clear(); e[i].clear(); edge[i].clear(); } while(m--) { scanf("%d%d",&a,&b); e[a].push_back(b); } solve(); memset(in,0,sizeof in); memset(out,0,sizeof out); int flag=1; for(i=1;i<=n;i++) { for(j=0;j<e[i].size();j++) { a=inpart[i]; b=inpart[e[i][j]]; if(a!=b) { in[b]++; out[a]++; edge[a].push_back(b); } } } if(topo()) printf("Yes\n"); else printf("No\n"); } return 0; }
poj2762 Going from u to v or from v to u? --- 缩点+拓扑
时间: 2024-10-08 06:28:05