题意:给出一幅有向图,要求判断,判断在这幅图中的任意两点x,y,一定有一条路可以从x到y或从y到x。
思路:缩点+拓扑,一个连通分量一定是满足要求的,那么把连通分量缩成点,拓扑排序,若是在删除某点后,有两个点的入度都为0,则输出No;若能全部删除输出Yes。
#include<iostream>
using namespace std;
const int MAXN =1001;
int DFN[MAXN];
int LOW[MAXN];
int instack[MAXN];
int Stap[MAXN];
int Belong[MAXN];
bool new_map[MAXN][MAXN];
int in[MAXN];
bool vis[MAXN];
struct edge
{
int v,next;
}vetex[7000];
int head[MAXN];
int Stop,Bcnt,Dindex,N,k;
void add(int a,int b)
{
vetex[k].v = b;
vetex[k].next = head[a];
head[a] = k;k++;
}
void tarjan(int i)
{
int j;
DFN[i]=LOW[i]=++Dindex;
instack[i]=true;
Stap[++Stop]=i;
for (int k=head[i];k;k=vetex[k].next)
{
j=vetex[k].v;
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;
Belong[j]=Bcnt;
}
while (j!=i);
}
}
void solve()
{
int i;
Stop=Bcnt=Dindex=0;
memset(DFN,0,sizeof(DFN));
for (i=1;i<=N;i++)
if (!DFN[i])
tarjan(i);
}
void process(int j,int n)
{
for(int i=1;i!=n+1;i++)
{
if(new_map[j][i])
in[i]--;
}
}
int check(int n)
{
int count(0);
int t(0);
for(int i=1;i!=n+1;i++)
{
if(vis[i]==false&&in[i]==0)
{
t=i;
vis[i] = true;
count++;
}
}
if(t!=0)
process(t,n);
return count;
}
bool topo_sort(int n)
{
memset(vis,false,sizeof(vis));
for(int i=1;i!=n+1;i++)
{
if(check(n)>1)
return false;
}
return true;
}
int main()
{
int E,TT;
cin>>TT;
while(TT--)
{
cin>>N>>E;
k=1;
memset(in,0,sizeof(in));
memset(new_map,false,sizeof(new_map));
memset(head,false,sizeof(head));
for(int i=1;i!=E+1;i++)
{
int a,b;cin>>a>>b;
add(a,b);
}
solve();
for(int i=1;i!=N+1;i++)
{
for(int k=head[i];k;k=vetex[k].next)
{
int a = Belong[i];int b = Belong[vetex[k].v];
new_map[a][b] = true;
in[b]++;
}
}
if(topo_sort(Bcnt))
cout<<"Yes"<<endl;
else
cout<<"No"<<endl;
}
return 0;
}