题意:给出点的个数和单向边,构成图。问图中两点x,y是否满足“x可以走到y,或者y可以走到x,or的关系
思路:求出强连通分支,构建新图,如果新图是一个没有中断的”链表”,那么输出yes,否则输出no。判断是否为“链表”,用拓扑排序即可,每次排序的时候判断入度为0的是否只有一个,是则继续排,否则说明不是一个”链表“
#include<iostream>
#include<stack>
using namespace std;
struct Node
{
int dest;
struct Node *next;
}node[1005],nMap[1005],*p;
stack<int>Q;
bool Visited[1005],InStack[1005];
int dfn[1005],low[1005],belong[1005];
int n,m,nTime,belongNum;
int nMapInNum[1005];//缩点后新图的入度
void AddNode(int origin,int finish,struct Node tnode[])//添加节点
{
p=new struct Node;
p->dest=finish;
p->next=tnode[origin].next;
tnode[origin].next=p;
}
void init()//初始化
{
scanf("%d%d",&n,&m);
memset(Visited,false,sizeof(Visited));
memset(InStack,false,sizeof(InStack));
memset(nMapInNum,0,sizeof(nMapInNum));
belongNum=nTime=0;
int i,a,b;
for(i=1;i<=n;i++)
{
node[i].next=NULL;
nMap[i].next=NULL;
}
for(i=1;i<=m;i++)
{
scanf("%d%d",&a,&b);
AddNode(a,b,node);
}
while(!Q.empty())
Q.pop();
}
int min(int ta,int tb)
{
if(ta>tb) return tb;
return ta;
}
void Tarjan(int t)
{
dfn[t]=low[t]=++nTime;
Q.push(t);
Visited[t]=InStack[t]=true;
struct Node *q;
int x;
for(q=node[t].next;q!=NULL;q=q->next)
{
x=q->dest;
if(!Visited[x])
{
Tarjan(x);
low[t]=min(low[t],low[x]);
}
else if(InStack[x])
low[t]=dfn[x];
}
if(dfn[t]==low[t])
{
int top;
belongNum++;
do
{
top=Q.top();
belong[top]=belongNum;//缩点标记
InStack[top]=false;
Q.pop();
}while(top!=t);
}
}
bool topo()//如果新图是一个链表返回true,否则返回false
{
int emptyNum,emptySub;//emptyNum用于标记拓扑排序时入度为0的个数,下标(单个为空有效)
int i,k=belongNum;
//找出空的个数
emptyNum=0;
for(i=1;i<=belongNum;i++)
{
if(nMapInNum[i]==0)
{
emptyNum++;
emptySub=i;
}
}
if(emptyNum>1) return false;
struct Node *q;
while(k--)
{
emptyNum--;//当前点已经排好,不计入
//Visited[emptySub]=true;
int x;
for(q=nMap[emptySub].next;q!=NULL;q=q->next)
{
x=q->dest;
if(--nMapInNum[x]==0)
{
emptyNum++;
emptySub=x;
}
}
if(emptyNum>1) return false;
}
return true;
}
void doit()
{
int i;
for(i=1;i<=n;i++)
{
if(!Visited[i])
Tarjan(i);
}
//缩点,建立新图,并记录每个点的入度
struct Node *q;
int x;
for(i=1;i<=n;i++)
{
for(q=node[i].next;q!=NULL;q=q->next)
{
x=q->dest;
if(belong[i]!=belong[x])
{
AddNode(belong[i],belong[x],nMap);
nMapInNum[belong[x]]++;
}
}
}
//memset(Visited,false,sizeof(Visited));//用于拓扑排序记录某点是否已经排好
if(topo()) printf("Yes\n");
else printf("No\n");
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
init();
doit();
}
return 0;
}