Poj 3352 Road Construction & Poj 3177 Redundant Paths(邊雙連通分量+縮點)

Time Limit: 2000MS   Memory Limit: 65536K
Total Submissions: 9465   Accepted: 4699

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

題意:某個企業想把一個熱帶天堂島變成旅遊勝地,島上有N個旅遊景點,任意2個旅遊景點之間有路徑連通(注意不一定是直接連通)。而爲了給遊客提供更方便的服務,該企業要求道路部門在某些道路增加一些設施。

道路部門每次只會選擇一條道路施工,在該條道路施工完畢前,其他道路依然可以通行。然而有道路部門正在施工的道路,在施工完畢前是禁止遊客通行的。這就導致了在施工期間遊客可能無法到達一些景點。

爲了在施工期間所有旅遊景點依然能夠正常對遊客開放,該企業決定搭建一些臨時橋樑,使得不管道路部門選在哪條路進行施工,遊客都能夠到達所有旅遊景點。給出當下允許通行的R條道路,問該企業至少再搭建幾條臨時橋樑,才能使得遊客無視道路部門的存在到達所有旅遊景點?


分析:首先建立模型:給定一個連通的無向圖G,至少要添加幾條邊,才能使其變爲雙連通圖。模型很簡單,正在施工的道路我們可以認爲那條邊被刪除了。那麼一個圖G能夠在刪除任意一條邊後,仍然是連通的,當且僅當圖G至少爲雙連通的。

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

麼如果圖G有多個【邊雙連通分量】呢?至少應該添加多少條邊,才能使得任意兩個【邊雙連通分量】之間都是雙連通(也就是圖G是雙連通的)?

一個有橋的連通圖要變成雙連通圖的話,把雙連通子圖收縮爲一個點,形成一棵樹,需要加的邊樹爲(leaf+1/ 2,其中leaf爲葉子節點個數。

#include <iostream>
#include <cstdio>
#include <vector>
#include <stack>
#include <algorithm>
#include <cstring>
using namespace std;

const int maxn = 5e3 + 10; // 最大頂點數
const int maxm = 1e4 + 10; // 最大邊數
int head[maxn], vis[maxn], dfn[maxn], low[maxn], deg[maxn];

int n, cnt, k;

struct Edge {  // 定義邊
    int to, next;
} edge[maxm<<1];

struct Tarjan {
    // 初始化,建邊前調用
    void Init() {
        memset(head, -1, sizeof(head));
        memset(vis, 0, sizeof(vis));
        memset(dfn, 0, sizeof(dfn));
        memset(low, 0, sizeof(low));
        memset(deg, 0, sizeof(deg));
        cnt = 0;
    }
    // 建邊
    void Add_Edge(int u, int v) {
        edge[cnt].to = v;
        edge[cnt].next = head[u];
        head[u] = cnt++;
    }
    // 縮點
    void tarjan(int u, int fa) {
        vis[u] = 1;
        dfn[u] = low[u] = ++k;
        for(int i = head[u]; i != -1; i = edge[i].next) {
            int v = edge[i].to;
            if(vis[v] == 1 && v != fa)
                low[u] = min(low[u], dfn[v]);
            if(!vis[v]) {
                tarjan(v, u);
                low[u] = min(low[u], low[v]);
            }
        }
        vis[u] = 2;
    }
    // 返回 最少添加幾條邊使得整個圖是一個雙連通分量
    int solve() {
        k = 0;
        tarjan(1, 1);
        for(int u = 1; u <= n; u++) {
            for(int i = head[u]; i != -1; i = edge[i].next) {
                int v = edge[i].to;
                if(low[u] != low[v])
                    deg[low[u]]++; //算出縮點後每個點的度
            }
        }
        int leaf = 0;
        for(int i = 1; i <= n; i++)
            if(deg[i] == 1) // 度爲1 的爲葉子結點
                leaf++;
        return (leaf + 1) / 2;
    }
};

int main() {
    int m, u, v;
    Tarjan tar;
    while(~scanf("%d%d", &n, &m)) {
        tar.Init();
        for(int i = 0; i < m; i++) {
            scanf("%d%d", &u, &v);
            tar.Add_Edge(u, v);
            tar.Add_Edge(v, u);
        }
        printf("%d\n", tar.solve());
    }
    return 0;
}





Time Limit: 1000MS   Memory Limit: 65536K
Total Submissions: 10109   Accepted: 4358

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,至少要添加幾條邊,才能使其變爲雙連通圖。


這題是和上面一題一模一樣,只不過表述方式不同而已。

另外本題要注意的是,3352保證了沒有重邊,而本題有重邊,所以在建圖時要去重。

#include <iostream>
#include <cstdio>
#include <vector>
#include <stack>
#include <algorithm>
#include <cstring>
using namespace std;

const int maxn = 5e3 + 10; // 最大頂點數
const int maxm = 1e4 + 10; // 最大邊數
int head[maxn], vis[maxn], dfn[maxn], low[maxn], deg[maxn];

int n, cnt, k;

struct Edge {  // 定義邊
    int to, next;
} edge[maxm<<1];

struct Tarjan {
    // 初始化,建邊前調用
    void Init() {
        memset(head, -1, sizeof(head));
        memset(vis, 0, sizeof(vis));
        memset(dfn, 0, sizeof(dfn));
        memset(low, 0, sizeof(low));
        memset(deg, 0, sizeof(deg));
        cnt = 0;
    }
    // 建邊
    void Add_Edge(int u, int v) {
        edge[cnt].to = v;
        edge[cnt].next = head[u];
        head[u] = cnt++;
    }
    // 縮點
    void tarjan(int u, int fa) {
        vis[u] = 1;
        dfn[u] = low[u] = ++k;
        for(int i = head[u]; i != -1; i = edge[i].next) {
            int v = edge[i].to;
            if(vis[v] == 1 && v != fa)
                low[u] = min(low[u], dfn[v]);
            if(!vis[v]) {
                tarjan(v, u);
                low[u] = min(low[u], low[v]);
            }
        }
        vis[u] = 2;
    }
    // 返回 最少添加幾條邊使得整個圖是一個雙連通分量
    int solve() {
        k = 0;
        tarjan(1, 1);
        for(int u = 1; u <= n; u++) {
            for(int i = head[u]; i != -1; i = edge[i].next) {
                int v = edge[i].to;
                if(low[u] != low[v])
                    deg[low[u]]++; //算出縮點後每個點的度
            }
        }
        int leaf = 0;
        for(int i = 1; i <= n; i++)
            if(deg[i] == 1) // 度爲1 的爲葉子結點
                leaf++;
        return (leaf + 1) / 2;
    }
};

int main() {
    int m, u, v;
    Tarjan tar;
    while(~scanf("%d%d", &n, &m)) {
        tar.Init();
        for(int i = 0; i < m; i++) {
            scanf("%d%d", &u, &v);
            if(head[u] != -1 && edge[head[u]].to == v)  // 注意有重邊,加判斷去掉重邊
                continue;
            tar.Add_Edge(u, v);
            tar.Add_Edge(v, u);
        }
        printf("%d\n", tar.solve());
    }
    return 0;
}



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章