题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=3721
题目意思:
给一颗树,求移动一条边(边权值不变)到另外的位置,还是一棵树。求最小的树的直径。
解题思路:
充分利用树的直径的性质。
任何点的最远距离一定是树直径上的一个端点。
枚举每条边,分成两颗子树后,求出两颗子树的直径d1,d2,以及两颗树的任意点A的最大距离的最小值p1,p2.显然由树的直径的性质,知点A一定在树的直径上。
ans=min(ans,max(max(d1,d2),p1+p2+len)).
代码:
#include<iostream> #include<cmath> #include<cstdio> #include<sstream> #include<cstdlib> #include<string> #include<cstring> #include<algorithm> #include<vector> #include<map> #include<set> #include<stack> #include<list> #include<queue> #include<ctime> #include<bitset> #define eps 1e-6 #define INF 0x3f3f3f3f #define PI acos(-1.0) #define ll __int64 #define LL long long #define lson l,m,(rt<<1) #define rson m+1,r,(rt<<1)|1 #define M 1000000007 #pragma comment(linker, "/STACK:1024000000,1024000000") using namespace std; #define Maxn 3000 int cnt; struct Edge { int v,len; struct Edge * next; }edge[Maxn<<1],*head[Maxn<<1]; void add(int a,int b,int len) { ++cnt; edge[cnt].v=b,edge[cnt].len=len; edge[cnt].next=head[a]; head[a]=&edge[cnt]; } int ma[Maxn],mi[Maxn]; int Max,Min; void dfs1(int cur,int fa) { ma[cur]=mi[cur]=0; struct Edge * p=head[cur]; while(p) { int v=p->v; if(v!=fa) { dfs1(v,cur); if(p->len+ma[v]>ma[cur]) { mi[cur]=ma[cur]; ma[cur]=p->len+ma[v]; } else if(p->len+ma[v]>mi[cur]) mi[cur]=p->len+ma[v]; } p=p->next; } } void dfs2(int cur,int fa) { if(ma[cur]>Max) Max=ma[cur]; if(ma[cur]<Min) Min=ma[cur]; struct Edge * p=head[cur]; while(p) { int v=p->v; if(v!=fa) { if(p->len+ma[v]<ma[cur]) //最大距离不是从这个儿子过来的 ma[v]=p->len+ma[cur]; else if(p->len+mi[cur]>ma[v]) //最大距离就是这个儿子过来的 ma[v]=p->len+mi[cur]; else if(p->len+mi[cur]>mi[v]) mi[v]=p->len+mi[cur]; dfs2(v,cur); } p=p->next; } } int main() { int t,n; scanf("%d",&t); for(int ca=1;ca<=t;ca++) { scanf("%d",&n); cnt=0; memset(head,NULL,sizeof(head)); for(int i=1;i<n;i++) { int a,b,c; scanf("%d%d%d",&a,&b,&c); add(a,b,c); add(b,a,c); } int ans=INF; //printf("%d\n",cnt); for(int i=1;i<=cnt;i+=2) { //相邻两个编号为一条边 int u=edge[i].v,v=edge[i+1].v,len=edge[i].len;//枚举每一条边 int temp1,temp2; //printf("u:%d v:%d\n",u,v); Max=0,Min=INF; //Max表示树的直径,Min表示最大距离的最小值 dfs1(u,v);dfs2(u,v); len+=Min; temp1=Max; Max=0,Min=INF; dfs1(v,u),dfs2(v,u); //另外一颗子树 //printf(":%d %d\n",Min,Max); len+=Min; temp2=Max; len=max(max(temp1,temp2),len); if(len<ans) ans=len; //system("pause"); } printf("Case %d: %d\n",ca,ans); } return 0; }