Loading

POJ3177 Redundant Paths(e-DCC+缩点)

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.
 
忘记因为要成对变换,tot应该从1开始,这么个题调了一天,我是傻逼。
由题意很容易想到是边双,每个e-DCC内部任何两个点都至少有两条没有公共边的路可以相互到达,于是求出所有的边双后缩点,这样就得到了一棵树。
这时考虑所有度为1的点(即端点,因为必然要在这些点上连边,不然的话最终总是会有割边),我们随意取出两个度为1的点并把它们之间建一条边,结果就是少了两个度为1的点并且多了一个边双(可以脑补一下再进行一次缩点),如此总共添加上(leaf+1)/2条边后所有度为1的点就消失了,整棵树缩成了一个点。
因此这个题就是输出缩点后的树的度为1的点的个数。
代码是蓝书板子凑出来的。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
const int SIZE = 100010;
using namespace std;
int head[SIZE],ver[2*SIZE],Next[2*SIZE];
int dfn[SIZE],low[SIZE],n,m,tot,num;
bool bridge[2*SIZE];
int deg[SIZE]={0};
int c[SIZE]={0},dcc=0;

int hc[SIZE],vc[2*SIZE],nc[2*SIZE],tc=0;
void add_c(int x,int y)
{
    vc[++tc]=y,nc[tc]=hc[x],hc[x]=tc;
}
void add(int x,int y)
{
    ver[++tot]=y,Next[tot]=head[x],head[x]=tot;
}
void tarjan(int x,int in_edge)
{
    dfn[x]=low[x]= ++num;
    int i;
    for(i=head[x];i;i=Next[i])
    {
        int y=ver[i];
        if(!dfn[y])
        {
            tarjan(y,i);
            low[x]=min(low[x],low[y]);
            if(low[y]>dfn[x]) bridge[i]=bridge[i ^ 1] = true;
        }
        else if(i!=(in_edge ^ 1)) low[x]=min(low[x],dfn[y]);
    }
}
void dfs(int x)
{
    c[x]=dcc;
    int i;
    for(i=head[x];i;i=Next[i])
    {
        int y=ver[i];
        if(c[y]||bridge[i]) continue;
        dfs(y);
    } 
}
int main()
{
    cin>>n>>m;
    int i;
    tot=1;
    for(i=1;i<=m;i++)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        add(x,y);
        add(y,x);
    }
    for(i=1;i<=n;i++)
    {
        if(!dfn[i]) tarjan(i,0);
    }
    for(i=1;i<=n;i++)
    {
        if(!c[i])
        {
            ++dcc;
            dfs(i);
        }
    }
    tc=1;
    for(i=2;i<=tot;i++)
    {
        int x=ver[i^1],y=ver[i];
        if(c[x]==c[y])continue;
        add_c(c[x],c[y]);
        deg[c[x]]++,deg[c[y]]++;
    }
    int number=0;
    if(dcc==2)
    {
        cout<<1<<endl;
        return 0;
    }
    for(i=1;i<=dcc;i++)
    {
        if(deg[i]==2) number++;
    }
    cout<<(number+1)/2;
    return 0;
}

 

 
 
 
posted @ 2020-05-05 23:33  脂环  阅读(252)  评论(0编辑  收藏  举报