先写下证明:(相信有人跟我一样不理解为什么K==2时第一条链必须选择直径,不能选两条不相交的次长链由于直径+相交的次长链嘛)看图:
直径A-B
先考虑如果不选直径,选两条次长链:
A-2 B-3 (显然不选1-2,否则1-B就是直径,点4同理不选,而且为了更优,肯定选择不相交的两条,如果相交不如选择直径加其中一条长链)
长度为: AD+D2+3E+EB;
而选择直径+次长链:的长度为AD+DE+EB+3E+D2-DE与前者长度刚好相同
(如果DE过长即3D+D2<DE则我们直接选取max(3E,D2),长度为:AD+DE+EB+max(3E+D2),也是不小于第一种情况的。)
发现:最优情况前者也只是等于后者,所以选直径+次长链是最优情况。、
综上:K==2时,先选择直径,再选则一条长链,是优解。
然后思路就简单了:、
先选择直径,然后把直径上的边都赋值成-1,表示选择边就会使结果变差1.
再在这个新的边权树上选择最长链。
结果就是:2*(n-1)-(L1-1)-(L2-1)
注意直径不能用两次dfs//因为有负边权,第一次dfs选的不一定是直径的端点,反例很好找。
然后就是一些细节问题,具体见代码!
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define ls (o<<1)
#define rs (o<<1|1)
#define pb push_back
const double PI= acos(-1.0);
const int M = 1e5+7;
int head[M],cnt;
void init(){cnt=0,memset(head,0,sizeof(head));}
struct EDGE{int to,nxt,w;}ee[M*2];
void add(int x,int y,int w){ee[++cnt].nxt=head[x],ee[cnt].w=w,ee[cnt].to=y,head[x]=cnt;}
int vs[M],f[M],dp[M];
int p,q,mx=-1;
void dfs(int x,int fa,int dep)
{
if(mx<dep)mx=dep,p=x;
for(int i=head[x];i;i=ee[i].nxt)
{
int y=ee[i].to;
if(y==fa)continue;
if(q!=0)f[y]=x;
dfs(y,x,dep+1);
}
}
int ans;
void dfs2(int x,int fa)
{
for(int i=head[x];i;i=ee[i].nxt)
{
int y=ee[i].to,w=1;
if(y==fa)continue;
if(vs[x]&&vs[y])w=-1;
dfs2(y,x);
ans=max(ans,dp[x]+dp[y]+w);
dp[x]=max(dp[y]+w,dp[x]);
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int n,k;
cin>>n>>k;
for(int i=1;i<n;i++)
{
int u,v;
cin>>u>>v;
add(u,v,1);
add(v,u,1);
}
mx=0;dfs(1,0,0);q=p;
mx=0;dfs(p,0,0);
//cout<<p<<" "<<q<<endl;
if(k==1)
{
cout<<2*(n-1)-mx+1<<endl;
return 0;
}
while(p!=0)
{
vs[p]=1;
p=f[p];
}
dfs2(1,0);
mx+=ans;
cout<<2*(n-1)-mx+2<<endl;
return 0;
}