求有向图的弱连通分量。将有向图的所有的有向边替换为无向边,所得到的图称为原图的基图。如果一个有向图的基图是连通图,则有向图是弱连通图。如果有向图中,对于任意节点v1和v2,至少存在从v1到v2和从v2到v1的路径中的一条,则原图为单向连通图。即设G=<V,E>是有向图,如果u->v意味着图G至多包含一条从u到v的简单路径,则图G为单连通图。强连通图、连通图、单向连通图三者之间的关系是,强连通图必然是单向连通的,单向连通图必然是弱连通图。
做法就是:先强连通缩点,形成一棵树或者森林,如果存在一个连接各个点的单链,那么满足弱连通的条件,单链就是指不能有分叉,使用拓扑排序解决这个问题。
代码:
#include <stack>
#include <queue>
#include <vector>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 1010;
const int M = 6010;
queue <int> Q;
stack <int> S;
vector <int> vt[N];
vector <int> graph[N];
int n, m;
int in[N],map[N][N];
int dfs_clock, point, vis[N], pre[N], belong[N], low[N];
void init(){
while(!S.empty()) S.pop();
while(!Q.empty()) Q.pop();
for(int i=1; i<=n; i++){
vt[i].clear();
graph[i].clear();
vis[i] = 0;
pre[i] = 0;
in[i] = 0;
}
memset(map, 0, sizeof(map));
dfs_clock = point = 0;
}
void Tarjan(int u){//强连通缩点
pre[u] = low[u] = ++dfs_clock;
vis[u] = 1;
S.push(u);
for(int i=0; i<vt[u].size(); i++){
int v = vt[u][i];
if(!pre[v]){
Tarjan(v);
low[u] = min(low[u], low[v]);
}
else if(vis[v] && pre[v] < low[u])
low[u] = pre[v];
}
if(pre[u] == low[u]){
point++;
int x;
do{
x = S.top();
vis[x] = 0;
belong[x] = point;
S.pop();
}while(u != x);
}
return;
}
bool topo_sort(){//拓扑排序
int sum = 0;
for(int i=1; i<=point; i++)
if(!in[i]){
sum++;
if(sum > 1) return false;
Q.push(i);
}
while(!Q.empty()){
int u = Q.front();
Q.pop();
int sum = 0;
for(int i=0; i<graph[u].size(); i++){
int v = graph[u][i];
in[v]--;
if(!in[v]){
sum++;
Q.push(v);
}
}
if(sum > 1) return false;
}
return true;
}
int main(){
int cas;
scanf("%d",&cas);
while(cas--){
scanf("%d%d", &n, &m);
/*if(n < 2){//刚开始就WA在这里
puts("No");
continue;
}*/
init();
for(int i=0; i<m; i++){
int u, v;
scanf("%d%d",&u, &v);
vt[u].push_back(v);
}
for(int i=1; i<=n; i++)
if(!pre[i]) Tarjan(i);
for(int i=1; i<=n; i++){
for(int j=0; j<vt[i].size(); j++){
int v = vt[i][j];
int a = belong[i], b = belong[v];
if(!map[a][b] && a != b){//重新建图,去掉重编
map[a][b] = 1;
graph[a].push_back(b);
in[b]++;
}
}
}
if(topo_sort()) puts("Yes");
else puts("No");
}
return 0;
}