(POJ 3352)无向图的边双连通分量模板题 + 在一个图中最少加几条边可以使得图边双连通

来源:互联网 发布:单片机延时1s程序 编辑:程序博客网 时间:2024/05/29 09:12

Road Construction
Time Limit: 2000MS Memory Limit: 65536K
Total Submissions: 11779 Accepted: 5899
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
Source

CCC 2007

题意:
在一个连通的无向图中,问你最少需要添加多少条边可以使得图边双连通?

分析:
1、求图G中的双连通分量。
2、每一个双联通分量缩成一个点,形成一棵树。
3、计算出叶子节点的个数,需要加的边的数量就是(叶子节点个数+1)/2。

为什么是(叶子节点数+1) / 2?因为只要我们用一条边连接两个叶子节点,那么这两个双联通分量就变成了一个双联通分量了。 为了不出现特殊情况,我们在选择两个叶子节点时要选择两个距离尽量远的叶子节点进行连接

AC代码:

#include <stdio.h>#include <string.h>const int MAXN=1005;struct node{    int to,next;} edge[MAXN*5];int head[MAXN],dfn[MAXN],low[MAXN],stack1[MAXN],cou[MAXN],n,m,time,cnt,top;bool vis[MAXN];void init(){    memset(vis,0,sizeof(vis));    memset(head,-1,sizeof(head));    memset(dfn,0,sizeof(dfn));    memset(low,0,sizeof(low));    memset(cou,0,sizeof(cou));    top=0;    cnt=0;    time=1;}int min(int a,int b){    if(a>b)a=b;    return a;}void addedge(int u,int v){    edge[cnt].to=v;    edge[cnt].next=head[u];    head[u]=cnt;    cnt++;}void dfs(int u,int fa){    dfn[u]=time;    low[u]=time;    time++;    vis[u]=true;    stack1[top]=u;    top++;    for(int i=head[u]; i!=-1; i=edge[i].next)    {        int v=edge[i].to;        if(!vis[v])        {            dfs(v,u);            low[u]=min(low[u],low[v]);        }        else if(v != fa && dfn[u] > dfn[v])        {            low[u]=min(low[u],dfn[v]);        }    }    /*    if(dfn[u]==low[u])    {        while(stack1[top]!=u&&top>0)        {            //cout<<stack1[top-1]<<endl;            low[stack1[top-1]]=low[u];            top--;        }    }    */}int main(){    int u,v;    while(scanf("%d%d",&n,&m)!=EOF)    {        init();        for(int i=0; i<m; i++)        {            scanf("%d%d",&u,&v);            u--;            v--;            addedge(u,v); //无向图加双向边            addedge(v,u);        }        dfs(0,-1); //因为图是联通的,只要DFS一个点,全图都可以搜到        for(int i=0; i<n; i++)        {            for(int j=head[i]; j!=-1; j=edge[j].next)            {                if(low[i]!=low[edge[j].to])                {                    cou[low[i]]++;                    cou[low[edge[j].to]]++;                }            }        }        cnt=0;        for(int i=0; i<=n; i++)        {            if(cou[i]/2==1)cnt++;        }        printf("%d\n",(cnt+1)/2);    }    return 0;}

这道题不需要被注释部分的代码,因为经过dfs后,所有的节点low[]值已经被更新为能到达的最早的祖先的dfn值了。这里显示出来只是因为可以作为模板,今后可能其他的题目需要输出所有的双连通分量等的情况

2 0
原创粉丝点击