
奶牛圆舞:N头牛,M条有向绳子,能组成几个歌舞团?要求顺时针逆时针都能带动舞团内所有牛。
4.3成为图论大师之路
强连通分量分解
睡不着,刷一题解解闷。
所谓能带动,就是舞团构成一个强连通分量,就是赤裸裸的SCC。
#include <iostream>
#include <cstring>
#include <vector>
using namespace std;
#define MAX_V 10000
int V; // 顶点数
vector<int> G[MAX_V]; // 图的邻接表表示
vector<int> rG[MAX_V]; // 反向图
vector<int> vs; // 后序遍历顺序的顶点列表
bool used[MAX_V]; // 访问标记
int cmp[MAX_V]; // 所属强连通分量的拓补序
void add_edge(const int &from, const int &to)
{
G[from].push_back(to);
rG[to].push_back(from);
}
void dfs(const int &v)
{
used[v] = true;
for (int i = 0; i < G[v].size(); ++i)
{
if (!used[G[v][i]])
dfs(G[v][i]);
}
vs.push_back(v);
}
void rdfs(const int &v, const int &k)
{
used[v] = true;
cmp[v] = k;
for (int i = 0; i < rG[v].size(); ++i)
{
if (!used[rG[v][i]])
rdfs(rG[v][i], k);
}
}
int scc()
{
memset(used, 0, sizeof(used));
vs.clear();
for (int v = 0; v < V; ++v)
{
if (!used[v])
dfs(v);
}
memset(used, 0, sizeof(used));
int k = 0;
for (int i = vs.size() - 1; i >= 0; --i)
{
if (!used[vs[i]])
rdfs(vs[i], k++);
}
return k;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
#endif
int m;
scanf("%d%d", &V, &m);
for (int _ = 0; _ < m; ++_)
{
int from, to;
scanf("%d%d", &from, &to);
--from;
--to;
add_edge(from, to);
}
int n = scc();
vector<int> count(n, 0);
for (int v = 0; v < V; ++v)
{
++count[cmp[v]];
}
int ans = 0;
for (int i = 0; i < n; ++i)
{
if (count[i] >= 2)
{
++ans;
}
}
printf("%d\n", ans);
#ifndef ONLINE_JUDGE
fclose(stdin);
#endif
return 0;
}
| 16237785 | hankcs | 3180 | Accepted | 1692K | 250MS | C++ | 1740B | 2016-10-28 15:16:07 |
知识共享署名-非商业性使用-相同方式共享:码农场 » POJ 3180 The Cow Prom 题解《挑战程序设计竞赛》
码农场