题目:http://acm.hdu.edu.cn/showproblem.php?pid=1269
连通分量, 断断续续看了几天, 今天终于A了道强联通分量(SCC)模板题。 初学SCC, 理解的还不是很好, 是利用Dfs中回溯过程进行操作, 细节掌握还不够好。
本题题意是判断有向图中SCC 个数是否唯一, 模板题;
#include <stack>
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
const int N = 10001;
struct Edge
{
int from, to, next;
} edge[100100];
int n, m, cnt, cnt_SCC, vis_num, low[N], tim[N], head[N], instack[N];
void Add(int a, int b)
{
Edge E = {a, b, head[a]};
edge[cnt] = E;
head[a] = cnt++;
}
stack <int>S;
void TarJan(int x)
{
int j;
tim[x] = low[x] = ++vis_num;
instack[x] = 1;
S.push(x);
for(int i = head[x]; i != -1; i = edge[i].next)
{
int u = edge[i].to;
if(tim[u] == -1)
{
TarJan(u);
if(low[x] > low[u])
low[x] = low[u];
}
else if(instack[u] && low[x] > tim[u])
low[x] = tim[u];
}
if(low[x] == tim[x])
{
cnt_SCC++;
do{
j = S.top();
S.pop();
instack[j] = 0;
} while(j != x);
}
}
void Solve()
{
vis_num = cnt_SCC = 0;
for(int i = 1; i <= n; i++)
if(tim[i] == -1)
TarJan(i);
if(cnt_SCC == 1)
puts("Yes");
else
puts("No");
}
void GetMap()
{
int a, b;
memset(instack, 0, sizeof(instack));
memset(low, 0, sizeof(low));
memset(tim, -1, sizeof(tim));
cnt = 0;
memset(head, -1, sizeof(head));
while(m--)
{
scanf("%d%d", &a, &b);
Add(a, b);
}
}
int main()
{
while(~scanf("%d%d", &n, &m), n+m)
{
GetMap();
Solve();
}
return 0; }
MyGod
1 大神解析(SCC_TarJan): 2 http://blog.sina.com.cn/s/blog_7a1746820100vtk9.html 3 http://www.cnblogs.com/saltless/archive/2010/11/08/1871430.html
贴个并查集做法, 并查集有点好用。 两个并查集,一个反向处理有向边。
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
int father[3][10001];
int find(int a, int i)
{
if(father[i][a] == a)
return a;
else
return find(father[i][a], i);
}
int n, m;
void mercy(int a , int b)
{
int P, Q;
if(a != n) //Important;
{
P = find(a, 0);
Q = find(b, 0);
if(P != Q)
father[0][a] = b; // Detail;
}
if(b != n)
{
P = find(a, 1);
Q = find(b, 1);
if(P != Q)
father[1][b] = a;
}
}
int main()
{
while(~scanf("%d%d", &n, &m), n+m)
{
for(int i = 1; i <= n; i++)
father[0][i] = father[1][i] = i;
for(int i = 1; i <= m; i++)
{
int a, b;
scanf("%d%d", &a, &b);
mercy(a, b);
}
bool flag = true;
for(int i = 1; i <= n; i++)
{
if(find(i, 0) != n || find(i, 1) != n)
{
flag = false;
break;
}
}
if(flag)
printf("Yes\n");
else
printf("No\n");
}
return 0;
}