您的位置:首页 > 产品设计 > UI/UE

树形dp-hdu-3721-Building Roads

2013-10-11 14:58 393 查看
题目链接:

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