HDU 4714 Tree2cycle 解题报告

题目

比赛

题意:

一棵树,删一条边或加一条边的花费都是1.求将这棵树变成以条包含全部点的没有多余边的环的最小花费。

题解:

也就是,先将树分成尽可能少的m条链,然后再把这m条链首尾连起来,花费是2×m-1.

类似于树上最长链的做法,以每个点为根的树,求全部分成链的最少数目b,和去掉一条链的最少数目a。前者可选两棵子树的a加上其它子树的b,后者同理,详见代码。


//Time:1359ms
//Memory:59968KB
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
using namespace std;
#define FI first
#define SE second
#define MP(x,y) make_pair(x,y)
const int MAXN= 2000010;
const double EPS = 1e-8;
const int INF = 1000000007;

int he[MAXN],to[MAXN],nex[MAXN],top;
void add(int u,int v)
{
    to[top]=v;
    nex[top]=he[u];
    he[u]=top++;
}
pair<int,int> dfs(int h,int fa)
{
    int b=0,on=0,tw=0;
    for(int i=he[h];i!=-1;i=nex[i])
        if(fa!=to[i])
        {
            pair<int,int> tmp=dfs(to[i],h);
            b+=tmp.SE+1;
            if(on>tmp.FI-tmp.SE-1)    tw=on,on=tmp.FI-tmp.SE-1;
            else    if(tw>tmp.FI-tmp.SE-1)    tw=tmp.FI-tmp.SE-1;
        }

    return MP(b+on,b+on+tw);
}
int main()
{
    //freopen("/home/moor/Code/input","r",stdin);
    int n,ncase,a,b;
    scanf("%d",&ncase);
    while(ncase--)
    {
        scanf("%d",&n);
        top=0;
        memset(he,-1,sizeof(he));
        for(int i=1;i<n;++i)    scanf("%d%d",&a,&b),add(a,b),add(b,a);
        printf("%d\n",dfs(1,-1).SE*2+1);
    }
    return 0;
}


你可能感兴趣的:(HDU 4714 Tree2cycle 解题报告)