演算法思路:很明顯的求有向圖的強連通分量的題。
可以用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;}