zjut1627驱车自驾游

View Code
#include<iostream>
#include<algorithm>
using namespace std;
#define MAXN 1111
int u[6*MAXN],v[6*MAXN],head[MAXN],next[6*MAXN],U[6*MAXN],V[6*MAXN];
int DFN[MAXN],LOW[MAXN],instack[MAXN],Stap[MAXN],ID[MAXN],In[MAXN];
int Dindex,Stop,Bcnt;
int cas,n,m,num;
void tarjan(int i)//缩点
{
int j;
DFN[i]=LOW[i]=++Dindex;
instack[i]=true;
Stap[++Stop]=i;
for(int e=head[i];e>=0;e=next[e])
{
j=v[e];
if(!DFN[j])
{
tarjan(j);
if(LOW[j]<LOW[i])
LOW[i]=LOW[j];
}
else if(instack[j]&&DFN[j]<LOW[i])
LOW[i]=DFN[j];
}
if(DFN[i]==LOW[i])
{
Bcnt++;
do
{
j=Stap[Stop--];
instack[j]=false;
ID[j]=Bcnt;
}while(j!=i);
}
}
void pro()
{
Dindex=Stop=Bcnt=0;
memset(DFN,0,sizeof(DFN));
memset(ID,-1,sizeof(ID));
for(int i=1;i<=n;i++)
if(!DFN[i])tarjan(i);
memset(head,-1,sizeof(head));
num=0;
for(int i=0;i<m;i++)//重新建边
{
int s=u[i];
int t=v[i];
if(ID[s]!=ID[t])
{
U[num]=ID[s];
V[num]=ID[t];
next[num]=head[U[num]];
head[U[num]]=num;
num++;
}
}
}
bool topo()
{
memset(In,0,sizeof(In));
for(int i=0;i<num;i++)//计算入度
In[V[i]]++;

for(int i=1;i<=Bcnt;i++)
{
int cnt0=0,sta=-1;
for(int j=1;j<=Bcnt;j++)
{
if(In[j]==0){cnt0++;sta=j;In[j]=-1;}
if(cnt0>1)return false;//入度为0的点超过1
}
for(int e=head[sta];e>=0;e=next[e])
In[V[e]]--;
}
return true;
}
int main()
{
scanf("%d",&cas);
while(cas--)
{
scanf("%d%d",&n,&m);
memset(head,-1,sizeof(head));
for(int i=0;i<m;i++)
{
scanf("%d%d",&u[i],&v[i]);
next[i]=head[u[i]];
head[u[i]]=i;
}
pro();
if(topo())printf("Yes\n");
else printf("No\n");
}
}


/*zjut1627驱车自驾游
图的弱连通
题意:判断有向图中 是否任意两点可达 u->v或v->u
图中一定存在一条路经过所有点,拓扑排序 当入度为0的点超过一个时,说明这些点的前驱已经被删,这几互不点不可达
缩点+拓扑
*/

原文地址:https://www.cnblogs.com/sook/p/2246381.html