您的位置:首页 > 其它

POJ 3352--Road Construction【无向图增加最少的边成为边双连通图 && tarjan求ebc && 缩点构造缩点树】

2015-08-18 16:40 411 查看
Road Construction

Time Limit: 2000MSMemory Limit: 65536K
Total Submissions: 9986Accepted: 4952
Description

It's almost summer time, and that means that it's almost summer construction time! This year, the good people who are in charge of the roads on the tropical island paradise of Remote Island would like to repair and upgrade the various roads that lead between
the various tourist attractions on the island.

The roads themselves are also rather interesting. Due to the strange customs of the island, the roads are arranged so that they never meet at intersections, but rather pass over or under each other using bridges and tunnels. In this way, each road runs between
two specific tourist attractions, so that the tourists do not become irreparably lost.

Unfortunately, given the nature of the repairs and upgrades needed on each road, when the construction company works on a particular road, it is unusable in either direction. This could cause a problem if it becomes impossible to travel between two tourist
attractions, even if the construction company works on only one road at any particular time.

So, the Road Department of Remote Island has decided to call upon your consulting services to help remedy this problem. It has been decided that new roads will have to be built between the various attractions in such a way that in the final configuration,
if any one road is undergoing construction, it would still be possible to travel between any two tourist attractions using the remaining roads. Your task is to find the minimum number of new roads necessary.

Input

The first line of input will consist of positive integers n and r, separated by a space, where 3 ≤ n ≤ 1000 is the number of tourist attractions on the island, and 2 ≤ r ≤ 1000 is the number of roads. The tourist attractions
are conveniently labelled from 1 to n. Each of the following r lines will consist of two integers, v and w, separated by a space, indicating that a road exists between the attractions labelled v and w.
Note that you may travel in either direction down each road, and any pair of tourist attractions will have at most one road directly between them. Also, you are assured that in the current configuration, it is possible to travel between any two tourist attractions.

Output

One line, consisting of an integer, which gives the minimum number of roads that we need to add.

Sample Input
Sample Input 1
10 12
1 2
1 3
1 4
2 5
2 6
5 6
3 7
3 8
7 8
4 9
4 10
9 10

Sample Input 2
3 3
1 2
2 3
1 3

Sample Output
Output for Sample Input 1
2

Output for Sample Input 2
0


本题和 POJ 3177基本一样,这里我用了另一种方法来写,前面求ebc,缩点的方法一样,在计算缩点的度时有不同,想看另一种方法的可以点这里POJ 3177

题意:

某个企业想把一个热带天堂岛变成旅游胜地,岛上有N个旅游景点,任意2个旅游景点之间有路径连通(注意不一定是直接连通)。而为了给游客提供更方便的服务,该企业要求道路部门在某些道路增加一些设施。

道路部门每次只会选择一条道路施工,在该条道路施工完毕前,其他道路依然可以通行。然而有道路部门正在施工的道路,在施工完毕前是禁止游客通行的。这就导致了在施工期间游客可能无法到达一些景点。

为了在施工期间所有旅游景点依然能够正常对游客开放,该企业决定搭建一些临时桥梁,使得不管道路部门选在哪条路进行施工,游客都能够到达所有旅游景点。给出当下允许通行的R条道路,问该企业至少再搭建几条临时桥梁,才能使得游客无视道路部门的存在到达所有旅游景点?

思路:首先要找出图G的所有【边双连通分量】。把每一个【边双连通分量】都看做一个点(即【缩点】)

我们知道当图存在桥(割边)的时候,它必定不是双连通的。桥的两个端点必定分别属于图的两个【边双连通分量】(属于两个【缩点】)。

所以我们可以枚举所有的点,如 u 点, 看看与 u 相连的边有没有是桥的,如果有的话,那么u 所在的所在的一个【缩点】通过这个桥和另一个【缩点】相连。

我们把 u 点所在的【缩点】的度数加一。然后便利所有缩点,看看度数为1 的有几个。根据公式:

若要使得任意一棵树,在增加若干条边后,变成一个双连通图,那么

至少增加的边数 =( 这棵树总度数为1的结点数 + 1 )/ 2。

即可求出最少增加的边数。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <stack>
#define maxn 5010
#define maxm 20010
using namespace std;

int n, m;
struct node {
    //cut标记之后是桥
    int u, v, cut, next;
};
node edge[maxm];
int du[maxn];//存每个缩点的度数
int head[maxn], cnt;
int low[maxn], dfn[maxn];
//Belong数组的值是 1 ~ ebc_block
int Stack[maxn], Belong[maxn];
int ebc_block;//边双连通块数
int dfs_clock;
int top;//模拟栈的指针
bool Instack[maxn];

void init(){
    cnt = 0;
    memset(head, -1, sizeof(head));
}

void addedge(int u, int v){
    edge[cnt] = {u, v, 0, head[u]};
    head[u] = cnt++;
}

void getmap(){
    while(m--){
        int a, b;
        scanf("%d%d", &a, &b);
        addedge(a, b);
        addedge(b, a);
    }
}

void tarjan(int u, int per){
    int v;
    low[u] = dfn[u] = ++dfs_clock;
    Stack[top++] = u;
    Instack[u] = true;
    int have = 1;
    for(int i = head[u]; i != -1; i = edge[i].next){
        v = edge[i].v;
        if(v == per && have){
            have = 0;
            continue;
        }
        if(!dfn[v]){
            tarjan(v, u);
            low[u] = min(low[u], low[v]);
            if(low[v] > dfn[u]){
                edge[i].cut = 1;
                edge[i ^ 1].cut = 1;
            }
        }
        else if(Instack[v])
            low[u] = min(low[u], dfn[v]);
    }
    if(low[u] == dfn[u]){
        ebc_block++;
        do{
            v = Stack[--top];
            Instack[v] = false;
            Belong[v] = ebc_block;
        }while(v != u);
    }
}

void find(){
    memset(low, 0, sizeof(low));
    memset(dfn, 0, sizeof(dfn));
    memset(Belong, 0 ,sizeof(Belong));
    memset(Instack, false, sizeof(Instack));
    dfs_clock = ebc_block = top = 0;
    tarjan(1, -1);
}

void solve(){
    memset(du, 0, sizeof(du));
    //本题思想
    for(int i = 1; i <= n; ++i)
    for(int j = head[i]; j != -1; j = edge[j].next){
        if(edge[j].cut)
            du[Belong[i]]++;
    }
    int ans = 0;
    for(int i = 1; i <= ebc_block; ++i)
        if(du[i] == 1)
            ans++;
    printf("%d\n", (ans + 1) / 2);
}

int main (){
    while(scanf("%d%d", &n, &m) != EOF){
        init();
        getmap();
        find();
        solve();
    }
    return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: