放牧代码和思想
专注自然语言处理、机器学习算法
    时间有限,只有GitHub上的issue能及时处理,大约每周末一次。另外,不要叫我楼主,谢谢。

POJ 3713 Transferring Sylla​ 题解 《挑战程序设计竞赛》

目录

POJ 3713 Transferring Sylla

三连通图判断一个无向图是否三连通?

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​ 题解 《挑战程序设计竞赛》

分享到:更多 ()

评论 欢迎留言

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

我的开源项目

HanLP自然语言处理包基于DoubleArrayTrie的Aho Corasick自动机