一眼看出了是求树的直径,然而没学过可怎么破。。。
然后百度自学了一波
http://www.cnblogs.com/wuyiqi/archive/2012/04/08/2437424.html
大概方法就是任找一个点,找离他最远的点,此点必为直径的端点,然后以此为基准再找一个离他最远的点,连成的链即树的直径。(证明见上地址)
k=0,观察到每条边必走两遍,无关于出发点
k=1即一个裸的树的直径,原因是图中每个边都至少要走两次,加一条路可以少走一遍,而多加这条路的cost(1),设直径为len1,那么ans1=2(n-1)-len1+1
k=2,则在k=1的基础上考虑。再求一条次长链len2,最长链与次长链相交,那么若直接ans1-len2+1必然是错的。因为通过新建路,本来需要往返的边可以省去一次回去的花费,而一段链被跳过两次,则意味着根本没有被遍历到,于是每条边需要再加上两遍,减两遍加两遍,二者相抵,即第二次需要将两次相重的再加回来。而不能先计算再加,因为有可能加的值(即相重的边)会很大,于是先进行等效的-1操作,将第一次选的链上所有边权改为-1,再找次长链。
而这里有一个问题,即上方给出的树的直径寻法针对的是正权(证明的条件是加边则必然权会更大),而负权就会很尴尬了。。。
其实搞一个树形DP就好了,每个节点记一个最长链和次长链,二者通过lca相连,每次记录一下,DP完以后ans2=2(n-1)-len1+1-len2+1即可
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn=100005;
struct edge
{
int to,next,val;
}e[maxn<<1];
int cnt=1,n,k,maxi,key,xx,yy;
int head[maxn],son1[maxn],son2[maxn];
void insert(int a,int b)
{
e[++cnt].to=b;e[cnt].val=1;e[cnt].next=head[a];head[a]=cnt;
}
int dfs(int x,int fa)
{
int max1,max2;
max1=max2=0;//自己到自己起码有一条0的路
son1[x]=son2[x]=x;
for(int i=head[x];i;i=e[i].next)if(e[i].to!=fa)
{
int now=e[i].val+dfs(e[i].to,x);
if(now>max1)
{
max2=max1;
max1=now;
son2[x]=son1[x];
son1[x]=son1[e[i].to];
}
else if(now>max2)
{
max2=now;
son2[x]=son1[e[i].to];
}
}
if(max1+max2>maxi)
{
maxi=max1+max2;
xx=son1[x];
yy=son2[x];
}
return max1;
}
void color(int x,int fa,int fin)
{
static bool flag=true;
for(int i=head[x];i&&flag;i=e[i].next)if(e[i].to!=fa)
{
e[i].val=e[i^1].val=-1;
if(e[i].to==fin)flag=false;
if(!flag)return;
color(e[i].to,x,fin);
if(!flag)return;
e[i].val=e[i^1].val=1;
}
}
int main()
{
scanf("%d%d",&n,&k);
for(int i=1,u,v;i<n;i++)
scanf("%d%d",&u,&v),
insert(u,v),
insert(v,u);
maxi=0;
dfs(1,-1);int len1=maxi;
if(k==1){printf("%d",2*(n-1)-len1+1);return 0;}
color(xx,-1,yy);
maxi=0;
dfs(1,-1);int len2=maxi;
printf("%d",2*(n-1)-len1+1-len2+1);
return 0;
}
k=1的情况:树的直径求法
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn=100005;
struct edge
{
int to,next,val;
}e[maxn<<1];
int cnt=1,n,k,maxi,key,xx,yy;
int head[maxn],dist[maxn];
void insert(int a,int b)
{
e[++cnt].to=b;e[cnt].val=1;e[cnt].next=head[a];head[a]=cnt;
}
void dfs(int x,int fa)
{
for(int i=head[x];i;i=e[i].next)if(e[i].to!=fa)
{
dist[e[i].to]=dist[x]+e[i].val;
if(dist[e[i].to]>maxi)key=e[i].to,maxi=dist[e[i].to];
dfs(e[i].to,x);
}
}
int length()
{
maxi=-0x3f3f3f3f;
memset(dist,0,sizeof dist);
dfs(1,-1);
memset(dist,0,sizeof dist);
xx=key;
maxi=-0x3f3f3f3f;
dfs(key,-1);
yy=key;
}
int main()
{
scanf("%d%d",&n,&k);
for(int i=1,u,v;i<n;i++)
scanf("%d%d",&u,&v),
insert(u,v),
insert(v,u);
length();int len1=maxi;
printf("%d",2*(n-1)-len1+1-len2+1);
}