算法思路:很明显的求有向图的强连通分量的题。
可以用tarjan算法,这也是比较常规的做法。但是在网上看到有人用并查集做的,相当神奇! 神奇的并查集!
方法转载自:http://everhythm.blog.163.com/blog/static/1794590792011113101019305/
思路 : 取定一个点n 第一个并查集表示 所有的点按一个方向都能到n 第二个并查集表示 把方向全反向 所有的点仍能到n 则强连通。具体可看代码,不过要真正地理解并查集的思想才容易明白。
以下代码是看过网上思路后自己重敲的,31msAC,不过刚开始写的时候没有在union函数中对a1、b1加相等的判断,导致死循环,TLE和stack overflow了好多次,输出的时候错把Yes打印为YES又WA了很多次。o(╯□╰)o
//模板开始
#include <string>
#include <vector>
#include <algorithm>
#include <iostream>
#include <sstream>
#include <fstream>
#include <map>
#include <set>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <iomanip>
#include <string.h>
#include <queue>
#define SZ(x) (int(x.size()))
using namespace std;
int toInt(string s){
istringstream sin(s);
int t;
sin>>t;
return t;
}
template<class T> string toString(T x){
ostringstream sout;
sout<<x;
return sout.str();
}
typedef long long int64;
int64 toInt64(string s){
istringstream sin(s);
int64 t;
sin>>t;
return t;
}
template<class T> T gcd(T a, T b){
if(a<0)
return gcd(-a, b);
if(b<0)
return gcd(a, -b);
return (b == 0)? a : gcd(b, a % b);
}
//模板结束(通用部分)
#define ifs cin
#define MAX_SIZE 10005
int pa1[MAX_SIZE]; //存储有向图的边
int pa2[MAX_SIZE]; //存储有向图的边
void init() //初始化 该函数可以根据具体情况保存和初始化需要的内容
{
for(int i = 0; i < MAX_SIZE; i++)
{
pa1[i] = i;
}
for(int i = 0; i < MAX_SIZE; i++)
{
pa2[i] = i;
}
}
int findset1(int x)
{
if(pa1[x] != x)
{
int root = findset1(pa1[x]);
return pa1[x] = root;
}
else
{
return x;
}
}
int findset2(int x)
{
if(pa2[x] != x)
{
int root = findset2(pa2[x]);
return pa2[x] = root;
}
else
{
return x;
}
}
void union_nodes1(int a, int b) //集合合并
{
int a1 = findset1(a);
int b1 = findset1(b);
if(a1 != b1)
{
pa1[a] = b;
}
}
void union_nodes2(int a, int b) //集合合并
{
int a1 = findset2(a);
int b1 = findset2(b);
if (a1 != b1)
{
pa2[a] = b;
}
}
//【图论04】有向图 1002 迷宫城堡
int main()
{
//ifstream ifs("shuju.txt", ios::in);
int n, m;
int a, b;
while(ifs>>n>>m && !(n == 0 && m == 0))
{
init();
for(int i = 0; i < m; i++)
{
//ifs>>a>>b;
scanf("%d%d", &a, &b);
if(a != n)
{
union_nodes1(a, b);
}
if(b != n)
{
union_nodes2(b, a);
}
}
int flag = 1;
for(int i = 1; i <= n - 1; i++)
{
//cout<<findset1(i)<<findset2(i)<<endl;
if(findset1(i) != n || findset2(i) != n)
{
flag = 0;
break;
}
}
if(flag)
{
cout<<"Yes"<<endl;
}
else
{
cout<<"No"<<endl;
}
}
return 0;
}
并查集解强连通分量
本文介绍了一种使用并查集解决有向图强连通分量问题的方法。通过建立两个并查集,分别表示从指定点可达的所有节点及反向可达的节点,最终确定所有节点是否构成强连通分量。

被折叠的 条评论
为什么被折叠?



