1. 程式人生 > >【ZBH選講·樹變環】

【ZBH選講·樹變環】

printf 忘記 lar 問題 分類 格式 約定 ret 思路

【問題描述】
你是能看到第三題的friends呢。
——aoao
樹是個好東西,刪掉樹一條邊要1的代價,隨便再加一條邊有1的代價,求最小的代價把樹變成環。
【輸入格式】
第一行一個整數,代表樹的點數。
接下來−1行,每行兩個數代表樹的一條邊。
【輸出格式】
一行一個整數代表答案。
【樣例輸入】
4
1 2
2 3
2 4
【樣例輸出】
3
【數據規模與約定】
對於30%的數據,1≤n≤10。
對於60%的數據,1≤n≤1000。
對於100%的數據,1≤n≤100000。

題解:
①這是貪心還是DP還是構造還是Implentation……(我們爭論了一會兒~)

②個人比較支持構造,最優的策略是:

思路:嘗試先將樹弄成一條鏈,最後加一條邊變成環。

分類討論:

(1)當前點僅有一個子節點,那麽什麽都不做。

(2)當前點有1個以上的依舊相連子節點,那麽此時最優的方案就是選取兩個兒子

組成一條鏈,其余的兒子的邊直接斷掉,並且將這個點和父親的連邊斷掉。

上述過程使用遞歸完成,並記錄斷邊個數x。

由於最後整個樹被拆成了x+1條鏈(或者點),然後在順次連x+1條邊就形成環。

因此最終答案就是x+x+1。

#include<cstdio>
#include<iostream>
#define N 100001
using namespace std;
int front[N],nxt[N<<1],to[N<<1],tot;
int ans;
void add(int u,int v)
{
    to[++tot]=v; nxt[tot]=front[u]; front[u]=tot;
    to[++tot]=u; nxt[tot]=front[v]; front[v]=tot;
}
int dfs(int x,int f)
{
    int sum=0;
    for(int i=front[x];i;i=nxt[i])if(to[i]!=f) sum+=dfs(to[i],x);
    if(sum>=2)
    {
        if(x==1) ans+=sum-2;
        else ans+=sum-1;
        return 0;
    }
    return 1;
}
int main()
{
    int n,u,v;scanf("%d",&n);
    for(int i=1;i<n;i++)scanf("%d%d",&u,&v),add(u,v);
    dfs(1,0);printf("%d",ans*2+1);
}//Ztraveler

點點滴滴往日的眷戀,尋尋覓覓又再回到我的身邊,

苦苦安頓撫平的回憶,驟然散落一如繁星的碎片……——————汪峰《回憶之前忘記之後》

【ZBH選講·樹變環】