传送门
题意:给你一个有向图,如果任意的u和v能从一个点走到另一个点,那就yes,否则no。一开始理解错题意,以为既要从u能到v又要从v能到u,结果wa了几发。。。。。。。
思路:强连通,缩点,对于新点最多只能1个入度为0,也最多1个出度为0,并且这两个不能是同一点。
#include<iostream> #include<cstdio> #include<cstring> #include<stack> using namespace std; int t,n,m,fst[1005],next[7000],node[7000]; int num,dfn[1005],low[1005],cnt,scnum,d[1005],in[1005],out[1005]; bool instack[1005],p[1005][1005]; stack<int>st; void init() { int u,v; num=0; cnt=0; scnum=0; memset(p,0,sizeof(p)); memset(fst,-1,sizeof(fst)); memset(in,0,sizeof(in)); memset(out,0,sizeof(out)); memset(dfn,0,sizeof(dfn)); memset(instack,0,sizeof(instack)); scanf("%d%d",&n,&m); for(int i=0;i<m;i++) { scanf("%d%d",&u,&v); if(!p[u][v]) { p[u][v]=1; next[++num]=fst[u]; fst[u]=num; node[num]=v; } } } void tarjan(int u) { int v; dfn[u]=low[u]=++cnt; st.push(u); instack[u]=1; for(int i=fst[u];i!=-1;i=next[i]) { v=node[i]; if(!dfn[v]) { tarjan(v); low[u]=min(low[u],low[v]); } else if(instack[v]) { low[u]=min(dfn[v],low[u]); } } if(low[u]==dfn[u]) { scnum++; do { v=st.top(); st.pop(); instack[v]=0; d[v]=scnum; }while(u!=v); } } int main() { scanf("%d",&t); while(t--) { init(); for(int i=1;i<=n;i++) { if(!dfn[i])tarjan(i); } for(int i=1;i<=n;i++) { for(int j=fst[i];j!=-1;j=next[j]) { int v=node[j]; if(d[i]!=d[v]) { out[d[i]]++; in[d[v]]++; } } } int flag=0; int x=0,y=0; for(int i=1;i<=scnum;i++) { //cout<<in[i]<<" "<<out[i]<<endl; if(in[i]==0&&out[i]==0) { flag=1; break; } else if(in[i]==0)x++; else if(out[i]==0)y++; } if(scnum==1)cout<<"Yes"<<endl; else if(flag)cout<<"No"<<endl; else if(x>1||y>1)cout<<"No"<<endl; else cout<<"Yes"<<endl; } return 0; }