题意:
一棵树,删一条边或加一条边的花费都是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;
}