码迷,mamicode.com
首页 > 其他好文 > 详细

POJ P3352 Road Construction 解题报告

时间:2018-06-09 18:00:06      阅读:137      评论:0      收藏:0      [点我收藏+]

标签:code   strong   lin   拓展   强连通分量   printf   for   空格   联通   

P3352 Road Construction

描述

这几乎是夏季,这意味着它几乎是夏季施工时间!今年,负责岛屿热带岛屿天堂道路的优秀人士,希望修复和升级岛上各个旅游景点之间的各种道路。

道路本身也很有趣。由于岛上奇特的风俗习惯,道路的布置使得它们不会在十字路口相遇,而是通过桥梁和隧道在彼此之间穿过或穿过。这样,每条道路都在两个特定的旅游景点之间运行,这样游客不会失去不可挽回的收入。

不幸的是,鉴于每条道路上所需的维修和升级的性质,当建筑公司在特定的道路上工作时,它在任何方向都不可用。如果不能在两个旅游景点之间旅行,即使建筑公司在任何特定时间只在一条道路上工作,这也可能导致问题。

因此,偏远岛道路部已决定请求您的咨询服务来帮助解决这个问题。已经决定在各个景点之间建造新的道路,使得在最终配置中,如果任何一条道路正在建设中,则仍有可能使用剩余道路在任何两个旅游景点之间旅行。你的任务是找到必要的最少数量的新道路。

输入

第一行输入由正整数\(n\)\(r\)组成,用空格隔开,其中\(3≤n≤1000\)是岛上旅游景点的数量,\(2≤r≤1000\)是道路数量。旅游景点可方便地标记为1至\(n\)。下列\(r\)行中的每一行都由两个整数组成,\(v\)\(w\)之间用空格隔开,表示标记为\(v\)\(w\)的景点之间存在道路。请注意,您可以沿着每条道路向两个方向行驶,任何一对旅游景点最多只能有一条道路在它们之间。此外,您可以放心,在目前的配置中,可以在任何两个旅游景点之间旅行。

输出

一行,由一个整数组成,它给出我们需要添加的最少道路数量。


谷歌翻译的。海星。

题目简化:对于一个联通图,加最少的边使图成为一个边双联通图。

可以看出,对于环上的任何一条边,割去都是没有影响的,我们可以先缩点,将图缩成一个树。然后对树做讨论。

对树中度为1的点,我们一定要把这个点再连一个边,此时用贪心的思想,同样使它连接其他度为1的点。对于度不为1的点,我们割去任何一条与它相连的边后它都可以通过度为1的点新连得边跑走。所以答案为\(\lceil d/2 \rceil\)

在做法上,也可以不缩点做,甚至是思想上。

在题目HNOI2012 矿场搭建中,我们用了这样的思想。

讨论每一个联通块中由割点相连接的若干个强连通分量(等效为去掉割点),讨论这个强连通分量与多少个割点相连做出决策。

对于这个题,我们可以考虑与割边相连的环。
若一个环与一个割边相连,则割去这个边后不能与其他的联通,得连走一条,等效为缩点后度为1的点。
若一个环与多个割边相连,无所谓啊。

【拓展】由此我们也可以由割边在无向图找环了。

这样写起来也比较简单了。


code:

#include <cstdio>
int min(int x,int y){return x<y?x:y;}
const int N=1010;
struct Edge
{
    int to,next;
}edge[N<<1];
int head[N],cnt=1,cntt=0,n,m;
void add(int u,int v)
{
    edge[++cnt].next=head[u];edge[cnt].to=v;head[u]=cnt;
}
int time=0,low[N],dfn[N],ans=0,c[N],is[N],used[N];
void tarjan(int now,int fa)
{
    low[now]=dfn[now]=++time;
    for(int i=head[now];i;i=edge[i].next)
    {
        int v=edge[i].to;
        if(!dfn[v])
        {
            tarjan(v,now);
            low[now]=min(low[v],low[now]);
            if(low[v]>dfn[now])
                is[i]=1,is[i^1]=1;
        }
        else if(fa!=v)
            low[now]=min(low[now],dfn[v]);
    }
}
void dfs(int now)
{
    used[now]=1;
    for(int i=head[now];i;i=edge[i].next)
    {
        int v=edge[i].to;
        if(is[i])
            cntt++;
        else if(!used[v])
            dfs(v);
    }
}
int main()
{
    scanf("%d%d",&n,&m);
    int u,v;
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d",&u,&v);
        add(u,v),add(v,u);
    }
    for(int i=1;i<=n;i++)
        tarjan(i,0);
    for(int i=1;i<=n;i++)
        if(!used[i])
        {
            cntt=0;
            dfs(i);
            if(cntt==1) ans++;
        }
    printf("%d\n",ans+1>>1);
    return 0;
}

2018.6.9

POJ P3352 Road Construction 解题报告

标签:code   strong   lin   拓展   强连通分量   printf   for   空格   联通   

原文地址:https://www.cnblogs.com/ppprseter/p/9160194.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!