1. 程式人生 > >POJ 3177--Redundant Paths【無向圖添加最少的邊成為邊雙連通圖 && tarjan求ebc && 縮點構造縮點樹】

POJ 3177--Redundant Paths【無向圖添加最少的邊成為邊雙連通圖 && tarjan求ebc && 縮點構造縮點樹】

when tab sub exp 無向圖 redundant -m term 一個點

Redundant Paths
Time Limit: 1000MS Memory Limit: 65536K
Total Submissions: 10798 Accepted: 4626

Description

In order to get from one of the F (1 <= F <= 5,000) grazing fields (which are numbered 1..F) to another field, Bessie and the rest of the herd are forced to cross near the Tree of Rotten Apples. The cows are now tired of often being forced to take a particular path and want to build some new paths so that they will always have a choice of at least two separate routes between any pair of fields. They currently have at least one route between each pair of fields and want to have at least two. Of course, they can only travel on Official Paths when they move from one field to another.

Given a description of the current set of R (F-1 <= R <= 10,000) paths that each connect exactly two different fields, determine the minimum number of new paths (each of which connects exactly two fields) that must be built so that there are at least two separate routes between any pair of fields. Routes are considered separate if they use none of the same paths, even if they visit the same intermediate field along the way.

There might already be more than one paths between the same pair of fields, and you may also build a new path that connects the same fields as some other path.

Input

Line 1: Two space-separated integers: F and R

Lines 2..R+1: Each line contains two space-separated integers which are the fields at the endpoints of some path.

Output

Line 1: A single integer that is the number of new paths that must be built.

Sample Input

7 7
1 2
2 3
3 4
2 5
4 5
5 6
5 7

Sample Output

2

Hint

Explanation of the sample:

One visualization of the paths is:
   1   2   3
   +---+---+  
       |   |
       |   |
 6 +---+---+ 4
      / 5
     / 
    / 
 7 +
Building new paths from 1 to 6 and from 4 to 7 satisfies the conditions.
   1   2   3
   +---+---+  
   :   |   |
   :   |   |
 6 +---+---+ 4
      / 5  :
     /     :
    /      :
 7 + - - - - 
Check some of the routes:
1 – 2: 1 –> 2 and 1 –> 6 –> 5 –> 2
1 – 4: 1 –> 2 –> 3 –> 4 and 1 –> 6 –> 5 –> 4
3 – 7: 3 –> 4 –> 7 and 3 –> 2 –> 5 –> 7

Every pair of fields is, in fact, connected by two routes.

It‘s possible that adding some other path will also solve the problem (like one from 6 to 7). Adding two paths, however, is the minimum.

下面解析來自:女神的博客

斌神博客上有個不錯的總結:斌神的博客


大致題意:

為了保護放牧環境,避免牲畜過度啃咬同一個地方的草皮,牧場主決定利用不斷遷移牲畜進行餵養的方法去保護牧草。然而牲畜在遷移過程中也會啃食路上的牧草,所以假設每次遷移都用同一條道路,那麽該條道路相同會被啃咬過度而遭受破壞。
如今牧場主擁有F個農場。已知這些農場至少有一條路徑連接起來(不一定是直接相連)。但從某些農場去另外一些農場。至少有一條路可通行。為了保護道路上的牧草,農場主希望再建造若幹條道路,使得每次遷移牲畜時,至少有2種遷移途徑,避免反復走上次遷移的道路。

已知當前有的R條道路。問農場主至少要新建造幾條道路,才幹滿足要求?


解題思路:
“使得每次遷移牲畜時,至少有2種遷移途徑,避免反復走上次遷移的道路。”就是說當吧F個農場看作點、路看作邊構造一個無向圖G時,圖G不存在橋。



那麽能夠建立模型:
給定一個連通的無向圖G,至少要加入幾條邊。才幹使其變為雙連通圖。

當圖G存在橋(割邊)的時候,它必然不是雙連通的。橋的兩個端點必然分別屬於圖G的兩個【邊雙連通分量】。一旦刪除了橋,這兩個【邊雙連通分量】必然斷開,圖G就不連通了。可是假設在兩個【邊雙連通分量】之間再加入一條邊。橋就不再是橋了。這兩個【邊雙連通分量】之間也就是雙連通了。

那麽假設圖G有多個【邊雙連通分量】呢?至少應該加入多少條邊,才幹使得隨意兩個【邊雙連通分量】之間都是雙連通(也就是圖G是雙連通的)

1、 首先要找出圖G的全部【邊雙連通分量】。

2、 把每個【邊雙連通分量】都看做一個點(即【縮點】)

3、 問題再次被轉化為“至少在縮點樹上添加多少條樹邊。使得這棵樹變為一個雙連通圖”。


首先知道一條等式:
若要使得隨意一棵樹。在添加若幹條邊後。變成一個雙連通圖,那麽
至少添加的邊數 =( 這棵樹總度數為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 {
    int u, v, 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, 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 pre){
    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(have && v == pre){//去重邊 
        	have = 0;
        	continue;
		}
        if(!dfn[v]){
            tarjan(v, u);
            low[u] = min(low[u], low[v]);
        }
        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 suodian(){
    memset(du, 0, sizeof(du));
    for(int i = 0; i < cnt; i += 2 ){
        int u = Belong[edge[i].u];
        int v = Belong[edge[i].v];
        if(u != v)
            du[u]++, du[v]++;
    }
}

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


void solve(){
    int ans = 0;
    if(ebc_block == 1){
        printf("0\n");
        return ;
    } 
    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();
        suodian();
        solve();
    }
    return 0;
}


POJ 3177--Redundant Paths【無向圖添加最少的邊成為邊雙連通圖 &amp;&amp; tarjan求ebc &amp;&amp; 縮點構造縮點樹】