zoukankan      html  css  js  c++  java
  • [Usaco2006 Jan] Redundant Paths 分离的路径

    1718: [Usaco2006 Jan] Redundant Paths 分离的路径

    Time Limit: 5 Sec  Memory Limit: 64 MB
    Submit: 1132  Solved: 590
    [Submit][Status][Discuss]

    Description

        为了从F(1≤F≤5000)个草场中的一个走到另一个,贝茜和她的同伴们有时不得不路过一些她们讨厌的可怕的树.奶牛们已经厌倦了被迫走某一条路,所以她们想建一些新路,使每一对草场之间都会至少有两条相互分离的路径,这样她们就有多一些选择.
        每对草场之间已经有至少一条路径.给出所有R(F-1≤R≤10000)条双向路的描述,每条路连接了两个不同的草场,请计算最少的新建道路的数量, 路径由若干道路首尾相连而成.两条路径相互分离,是指两条路径没有一条重合的道路.但是,两条分离的路径上可以有一些相同的草场. 对于同一对草场之间,可能已经有两条不同的道路,你也可以在它们之间再建一条道路,作为另一条不同的道路.

    Input

        第1行输入F和R,接下来R行,每行输入两个整数,表示两个草场,它们之间有一条道路.

    Output

        最少的需要新建的道路数.

    Sample Input

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

    Sample Output

    2

    HINT

    Source

    [Submit][Status][Discuss]
    
    HOME Back

    题解

    题意要求的是加最少的边让连通图变成边双。

    翻了好久才有一篇讲解了构造的题解

    首先tarjan把边双都缩成一个点。如果个数只有1或2,答案显然。

    然后是一棵树的情况,选择一个度数不为1的点(易证存在)做根节点。 如何把这棵树加最少的边变成边双呢?

    统计出树中度为1的节点的个数,即为叶节点的个数,记为leaf。则至少在树上添加(leaf+1)/2条边,就能使树达到边二连通,所以至少添加的边数就是(leaf+1)/2。具体方法为,首先把两个最近公共祖先最远的两个叶节点之间连接一条边,这样就可以再缩一次点。然后再找两个最近公共祖先最远的两个叶节点,这样一对一对找完,恰好是(leaf+1)/2次,把所有点收缩到了一起。

    为什么是正确的呢?考虑我们的目的,是让这棵树变成一个点。而如果这些叶节点都被上述那种找最长链的方式缩成一个点,那么整棵树也应该被缩成一个点了。还是感性理解啊……

    #include<bits/stdc++.h>
    #define rg register
    #define il inline
    #define co const
    template<class T>il T read(){
        rg T data=0,w=1;rg char ch=getchar();
        for(;!isdigit(ch);ch=getchar())if(ch=='-') w=-w;
        for(;isdigit(ch);ch=getchar()) data=data*10+ch-'0';
        return data*w;
    }
    template<class T>il T read(rg T&x) {return x=read<T>();}
    typedef long long ll;
    using namespace std;
    
    co int N=5e3+1,M=2e4+2;
    int n,m,dfn[N],low[N],num;
    int head[N],edge[M],next[M],tot=1;
    int st[N],top;
    int dcc[N],deg[N],cnt,ans;
    bool v[N];
    
    il void add(int x,int y){
    	edge[++tot]=y,next[tot]=head[x],head[x]=tot;
    }
    void tarjan(int x){
    	dfn[x]=low[x]=++num;
    	for(int i=head[x];i;i=next[i]){
    		if(v[i]) continue;
    		int y=edge[i];
    		if(!dfn[y]){
    			st[++top]=y;
    			v[i]=v[i^1]=1;
    			tarjan(y);
    			v[i]=v[i^1]=0;
    			low[x]=min(low[x],low[y]);
    		}
    		else low[x]=min(low[x],dfn[y]);
    	}
    	if(dfn[x]==low[x]){
    		++cnt;
    		while(top){
    			dcc[st[top]]=cnt;
    			if(st[top--]==x) break;
    		}
    	}
    }
    int main(){
    	read(n),read(m);
    	for(int x,y;m--;){
    		read(x),read(y);
    		add(x,y),add(y,x);
    	}
    	st[top=1]=1,tarjan(1);
    	for(int i=2;i<=tot;i+=2){
    		int x=edge[i],y=edge[i^1];
    		if(dcc[x]==dcc[y]) continue;
    		++deg[dcc[x]],++deg[dcc[y]];
    	}
    	for(int i=1;i<=n;++i) ans+=deg[i]==1;
    	printf("%d
    ",(ans+1)/2);
    	return 0;
    }
    
  • 相关阅读:
    洛谷 P1763 状态压缩dp+容斥原理
    hdu4612 Warm up 缩点+树的直径
    UVA-315 无向图求割点个数
    mysql 严格模式 Strict Mode说明
    bak文件恢复成 SQL2005 数据库 的全程讲解
    vps(windows2003)安全设置参考
    window下lamp环境搭建
    centos虚拟机配置网卡连接
    linux Tar 命令参数详解
    linux 打包和压缩的概念和区别
  • 原文地址:https://www.cnblogs.com/autoint/p/11045930.html
Copyright © 2011-2022 走看看