您的位置:首页 > 其它

HDU 4714 Tree2cycle 解题报告

2013-09-08 20:57 246 查看
题目

比赛

题意:

一棵树,删一条边或加一条边的花费都是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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: