![]()

三连通图:判断一个无向图是否三连通?
3.5借助水流解决问题的网络流
最大流
刷个题报平安,果然无论是主观还是客观我都闲不下来,明天加班!
三连通图指的是去掉3个点就不连通的图,但是并没有直接求三连通的算法。著名的Tarjan算法可以求解连通和割点,再枚举删除一个点就能达到三连通的目的。
先看用例2,是由用例1去掉一条边而变成非三连通图的:

至少造成了2和3非三连通:

我们来思考如何推导出2和3非三连通,假设从上图中删除了节点0,通过Tarjan算法,我们可以发现节点1是割点:

那么只需删除从3到割点和从3到我们枚举删除的节点0的两条边,就可以将3和2分割开来:

才删除了两条边2和3就不连通了,这个图显然不是三连通图。
#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>
using namespace std;
#define MAXN 512
vector<int> G[MAXN];
int V;
bool is_cut_vertex[MAXN]; // 是否是割点
int status[MAXN]; // 0:没有访问 1:正在访问 2:已经访问
int lowlink[MAXN]; // 从i出发经有向边可到达的所有结点中最小的index
int index[MAXN]; // 表示i节点在树中的深度
int root; // 根节点
bool has_cut_vertex; // 是否存在割点
void init(const int &v)
{
V = v;
has_cut_vertex = false;
for (int i = 0; i <= V; ++i)
{
G[i].clear();
}
}
void tarjan_dfs(int current, int from, int depth)
{
status[current] = 1; //正在访问
lowlink[current] = index[current] = depth; // 深度
int sub_tree = 0; //子树个数
int v;
for (vector<int>::const_iterator it = G[current].begin(), end = G[current].end(); it != end; ++it)
{
v = *it;
if (v != from && status[v] == 1)
{
lowlink[current] = min(lowlink[current], index[v]);
}
if (0 == status[v])
{
tarjan_dfs(v, current, depth + 1);
++sub_tree; //子树 +1
lowlink[current] = min(lowlink[current], lowlink[v]);
//求割点
if ((current == root && sub_tree > 1) || (current != root && lowlink[v] >= index[current]))
{
is_cut_vertex[current] = 1;
has_cut_vertex = true;
}
}
}
status[current] = 2;
}
void calc(int del)
{
memset(is_cut_vertex, 0, sizeof(is_cut_vertex));
memset(status, 0, sizeof(status));
memset(lowlink, 0, sizeof(lowlink));
memset(index, 0, sizeof(index));
status[del] = 2;
root = 0;
if (del == 0)
{
root = 1;
}
tarjan_dfs(root, -1, 1);
}
//求图是否是三连通
bool solve()
{
for (int i = 0; i < V; ++i)
{
calc(i);
//判断图是否连通
for (int j = 0; j < V; ++j)
{
if (0 == status[j])
{
has_cut_vertex = true;
break;
}
}
if (has_cut_vertex)
{
break;
}
}
return !has_cut_vertex;
}
///////////////////////////SubMain//////////////////////////////////
int main(int argc, char *argv[])
{
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
#endif
int N, M;
while (scanf("%d%d", &N, &M) && N)
{
init(N);
for (int _ = 0; _ < M; ++_)
{
int from, to;
scanf("%d%d", &from, &to);
G[from].push_back(to);
G[to].push_back(from);
}
puts(solve() ? "YES" : "NO");
}
#ifndef ONLINE_JUDGE
fclose(stdin);
#endif
return 0;
}
///////////////////////////End Sub//////////////////////////////////
| 13756424 | hankcs | 3713 | Accepted | 332K | 2625MS | C++ | 2889B | 2015-01-01 23:54:20 |
顺便这题没看出来跟最大流有什么关系。
知识共享署名-非商业性使用-相同方式共享:码农场 » POJ 3713 Transferring Sylla 题解 《挑战程序设计竞赛》
码农场