1. 程式人生 > >POJ P3352 Road Construction 解題報告

POJ P3352 Road Construction 解題報告

請求 聯通圖 優秀 任務 .cn %d hnoi2012 cnblogs 多個

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 解題報告