题意: 给你一个有向图,如果对于图中的任意一对点u和v都有一条从u到v的路或从v到u的路,那么就输出’Yes’,否则输出’No’.
理解:当出现两个及以上入度为0的点(有一个就可能是别人到它,有两个的话那么那两个就互相到不了,因为他们入度都为0),就必定有不满足连通性的,但是如果只是单纯判断出度入度,会将重边误算,所以应该要用拓扑排序。拓扑排序之前,应该先进行缩点。
注意:多组数据,要记得清0!!
#include<bits/stdc++.h> using namespace std; const int N=1e3+5; const int M=N*N; int to[M],t[M],head[N],hea[N],nex[M],ne[M],tot,tott; int cnt,T,stk[N],flag[N],low[N],vis[N],top,bel[N]; queue<int >q; int in[N]; void add1(int a,int b) { to[++tot]=b; nex[tot]=head[a]; head[a]=tot; } void add2(int a,int b) { t[++tott]=b; ne[tott]=hea[a]; hea[a]=tott; } void init() { top=0,tot=0,tott=0,cnt=0,T=0; memset(to,0,sizeof(to));memset(t,0,sizeof(t)); memset(head,0,sizeof(head));memset(hea,0,sizeof(hea)); memset(nex,0,sizeof(nex));memset(ne,0,sizeof(ne)); memset(vis,0,sizeof(vis));memset(low,0,sizeof(low)); memset(stk,0,sizeof(stk));memset(in,0,sizeof(in)); memset(flag,0,sizeof(flag)); while(!q.empty()) q.pop(); } void tarjan(int x) { vis[x]=low[x]=++T; stk[++top]=x; flag[x]=1; for(int i=head[x];i;i=nex[i]) { int v=to[i]; if(!vis[v]) { tarjan(v); low[x]=min(low[x],low[v]); } else if(flag[v]) low[x]=min(low[x],vis[v]); } if(vis[x]==low[x]) { cnt++; do{ flag[stk[top]]=0; bel[stk[top]]=cnt; }while(stk[top--]!=x); } } void build(int u) { for(int i=head[u];i;i=nex[i]) if(bel[u]!=bel[to[i]]) add2(bel[u],bel[to[i]]),in[bel[to[i]]]++;//bel[to[i]]!! } bool topo() { //printf("%d\n",cnt); for(int i=1;i<=cnt;i++) if(!in[i]) q.push(i); while(!q.empty()) { if(q.size()>1) return false; int u=q.front(); q.pop(); for(int i=hea[u];i;i=ne[i]) { int v=t[i]; in[v]--; if(!in[v]) q.push(v); } } return true; } int main() { freopen("graph.in","r",stdin); freopen("graph.out","w",stdout); int n,m,Ti,a,b; scanf("%d",&Ti); while(Ti--) { init(); scanf("%d%d",&n,&m); for(int i=1;i<=m;i++) scanf("%d%d",&a,&b),add1(a,b); for(int i=1;i<=n;i++) if(!vis[i]) tarjan(i); for(int i=1;i<=n;i++) build(i); if(!topo()) printf("No\n"); else printf("Yes\n"); } } /* 2 3 2 1 3 2 3 3 2 1 2 2 3 */