- -
更多关于tarjan算法扩展请关注 使劲戳→ tarjan算法扩展
题意:
给定有向图,问是否满足任意两点 x, y 使得 x->y 或 y->x 存在一条路径。
即 若缩点后新建图拓扑排序,图为单一的一条路径时,则输出Yes,反之No.
tarjan+缩点+拓扑排序
//拓扑排序,每次输出只能输出一个节点的时候(只有一条路),则为yes
附代码:
<pre name="code" class="cpp">#include <iostream>
#include <queue>
#include <vector>
#include <cstdio>
#include <algorithm>
using namespace std;
#define M 1010 //题目中可能的最大点数
int STACK[M],top=0; //Tarjan 算法中的栈
bool InStack[M]; //检查是否在栈中
int DFN[M]; //深度优先搜索访问次序
int Low[M]; //能追溯到的最早的次序
int Num=0; //有向图强连通分量个数
int Index=0; //索引号
vector <int> Edge[M]; //邻接表表示
vector <int> Component[M]; //获得强连通分量结果
int Belong[M]; //记录每个点在第几号强连通分量里
int Depth[M]; //记录每个强连通分量的度
int dep[M];
int n,m,cas;
void Tarjan(int i)
{
int j;
DFN[i]=Low[i]=Index++;
InStack[i]=true;
STACK[++top]=i;
for (int e=0;e<Edge[i].size();e++)
{
j=Edge[i][e];
if (DFN[j]==-1)
{
Tarjan(j);
Low[i]=min(Low[i],Low[j]);
}
else if (InStack[j]) //有向特点。
Low[i]=min(Low[i],DFN[j]);
}
if (DFN[i]==Low[i])
{
Num++;
do
{
j=STACK[top--];
InStack[j]=false;
Component[Num].push_back(j);
Belong[j]=Num;
Depth[Num]++;
}
while (j!=i);
}
}
void solve(int N) //N是此图中点的个数,注意是0-indexed! //需要注意的是点的坐标也是从1开始。
{
Index=top=Num=0;
memset(STACK,-1,sizeof(STACK));
memset(InStack,0,sizeof(InStack));
memset(DFN,-1,sizeof(DFN));
memset(Low,-1,sizeof(Low));
for(int i=1;i<=N;i++)
if(DFN[i]==-1)
Tarjan(i);
}
void topsort(bool &ok)
{
memset(dep,0,sizeof(dep));
vector<int>vec[M];
for(int i=1;i<=n;i++)
for(int j=0;j<Edge[i].size();i++)
if(Belong[i]!=Belong[Edge[i][j]])
{
dep[Belong[Edge[i][j]]]++;
vec[Belong[i]].push_back(Belong[Edge[i][j]]);
} //新建图以及计算度数
int sum=0;
queue<int>que;
for(int i=1;i<=Num;i++)
if(dep[i]==0)
que.push(i);
while(!que.empty())
{
if(que.size()!=1) //如果有多个节点,就不是单一的路径
{
ok=0;
return ;
}
int i=que.front();
que.pop();
sum++;
for(int j=0;j<vec[i].size();j++)
if(--dep[vec[i][j]]==0)
que.push(vec[i][j]);
}
if(sum!=Num)
ok=0;
}
int main()
{
scanf("%d",&cas);
while(cas--)
{
for(int i=1;i<=n;i++)
Edge[i].clear();
scanf("%d %d",&n,&m);
while(m--)
{
int a,b;
scanf("%d %d",&a,&b);
Edge[a].push_back(b);
}
solve(n);
bool ok=1;
topsort(ok);
if(ok)
printf("Yes\n");
else
printf("No\n");
}
return 0;
}