Poj 3352 Road Construction & Poj 3177 Redundant Paths(边双连通分量+缩点)

Road Construction

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;
}

Redundant Paths

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;
}
时间: 2024-10-16 12:08:06

Poj 3352 Road Construction & Poj 3177 Redundant Paths(边双连通分量+缩点)的相关文章

POJ 3177 Redundant Paths 边双连通分量+缩点

题目链接: poj3177 题意: 给出一张连通图,为了让任意两点都有两条通路(不能重边,可以重点),至少需要加多少条边 题解思路: 分析:在同一个边双连通分量中,任意两点都有至少两条独立路可达,所以同一个边双连通分量里的所有点可以看做同一个点. 缩点后,新图是一棵树,树的边就是原无向图桥. 现在问题转化为:在树中至少添加多少条边能使图变为双连通图. 结论:添加边数=(树中度为1的节点数+1)/2 具体方法为,首先把两个最近公共祖先最远的两个叶节点之间连接一条边,这样可以把这两个点到祖先的路径上

POJ 3352 Road Construction POJ 3177 Redundant Paths(边双连通图 Tarjan+缩点)

POJ 3352 Road Construction POJ 3177 Redundant Paths(边双连通图 Tarjan+缩点) ACM 题目地址: POJ 3352 Road Construction POJ 3177 Redundant Paths 题意: 问要添加几条边才能使所给无向图图变成边双连通图. 分析: 边连通度:使无向图G不连通的最少删边数量为其边连通度. 边双连通图:边连通度大于1的无向图. 首先缩点,让图变成一个DAG. 现在问题转化为:在树中至少添加多少条边能使图变

POJ 3352 Road Construction&amp;&amp; POJ 3177 Redundant Paths 双联通分量

大意:给定n点,和m条边的关系图中的一些边随时可能施工导致不能够通过,所以至少加多少条边才能够使得途中任意两条边联通? 思路:很明显只要图中的任意两点都是两条边来链接即可.那么我们可以先缩点构建新图,然后统计出度为1的点的个数ans,那么需要加的边数就是(ans+1)/2条; (PS;因为建图是双向的图所以,在Tarjan缩点的时候就需要遇到临边便越过,并且判断是不是同一个联通分支用num比较!) #include<map> #include<queue> #include<

POJ 3352 Road Construction(添最少边构造边双连通图的结论)

题意:已知无向图,问添加最少的边使之成为边双连通图 思路:显然先缩点成一棵树,添加最少边使一棵树的边双连通 此处有结论:对于一棵树添加(1+leaf)>>1 条无向边就能构造成一个双连通图,构造方法显然(脑补一下 //216K 63MS C++ 1754B #include<cstdio> #include<iostream> #include<cstring> #include<algorithm> using namespace std; c

POJ 3177 Redundant Paths POJ 3352 Road Construction(双连通)

POJ 3177 Redundant Paths POJ 3352 Road Construction 题目链接 题意:两题一样的,一份代码能交,给定一个连通无向图,问加几条边能使得图变成一个双连通图 思路:先求双连通,缩点后,计算入度为1的个数,然后(个数 + 1) / 2 就是答案(这题由于是只有一个连通块所以可以这么搞,如果有多个,就不能这样搞了) 代码: #include <cstdio> #include <cstring> #include <algorithm&

POJ 3352 Road Construction(图论-tarjan)

Road Construction Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 8647   Accepted: 4318 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 ro

POJ 3352 Road Construction 使得无向图边变双连通图

点击打开链接 Road Construction Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 8168   Accepted: 4106 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

poj3177 Redundant Paths 边双连通分量

#include <iostream> #include <cstring> #include <string> #include <cstdio> #include <cmath> #include <algorithm> #include <vector> #include <queue> #include <map> #define inf 0x3f3f3f3f #define eps 1e-

POJ - 3352 Road Construction(边双连通分支)

1.给定一个连通的无向图G,至少要添加几条边,才能使其变为双连通图. 2.POJ - 3177 Redundant Paths(边双连通分支)(模板)  与这道题一模一样.代码就改了下范围,其他都没动... 3. //边双连通分支 /* 去掉桥,其余的连通分支就是边双连通分支了.一个有桥的连通图要变成边双连通图的话, 把双连通子图收缩为一个点,形成一颗树.需要加的边为(leaf+1)/2(leaf为叶子结点的个数) POJ 3177 给定一个连通的无向图G,至少要添加几条边,才能使其变为双连通图