道路改建

来源:互联网 发布:网络基础架构设计方案 编辑:程序博客网 时间:2024/05/01 06:56

题目描述 一个由n户人家组成的村庄,用n-1条路径连接,形成一棵树。
现在进行道路改建,先把某条边的删除,再用这条边连接其他两个点(保持长度相同)。
使得最后村庄之间仍能相互到达,且最远的两个村庄之间的距离最小。
输入 第一行一个整数n,表示村庄的个数。
接下来n-1行,每行3个整数a、b、c,表示有一条路径连接编号为a和b的村庄(编号从0开始)。
输出 输出可以使最远距离达的最小值。
对于100%的数据,n的范围[1,5000],0≤a,b≤n-1,1≤c≤10000;

一道很不错的树的题目
主要的思考点在于
如何找到树上任意一结点的最远值和如何更新答案

根据题目描述
在切断一条边后
一棵树(A)会被分成两棵树(B,C)
这时答案会有三种情况:
1.B的直径
2.C的直径
3.两棵树重新连接后形成的新的直径

我们要做的就是使3最小
设新边连接两点为a,b
这个直径的组成为len1+len2+len3
len1为a在A树上的最远距离
len2为b在B树上的最远距离
len3为被删除边的长度

先在要解决的就是如何快速地求出每个点的最远距离
这里可以使用三遍dfs
第一次找到最远点x1
第二次找到直径的另一个端点x2(同时求出每个点到x1的距离)
第三次从x2出发,求出x2到任意点的距离
ps:节点的距离最大值一定是直径两个端点的任意一点

为了使代码较为简洁可以用结构体包起来

#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#include<vector>using namespace std;#define FOR(i,x,y) for(int i=(x);i<(y);i++)//左闭右开 #define DOR(i,x,y) for(int i=(x);i>(y);i--)#define M 5005#define oo 1000000000int n;inline void chk_mi(int &x,int y){if(x>y)x=y;}inline void chk_mx(int &x,int y){if(x<y)x=y;}//三遍dfs找到每个点的对应最远点struct node{int id,v;};vector<node>edge[M];struct Tree{    int mxdis,cdis;//树的直径 和 到最远点最近的距离     int pa,pb;//断开的两点    int dx;//树直径的一个端点    int fa[M][2];//第一维装父亲 第二位装大小    int dis[M];    void dfs(int x,int f,int d){        chk_mx(dis[x],d);        if(d>mxdis){mxdis=d;dx=x;}         FOR(i,0,edge[x].size()){            int y=edge[x][i].id;            if(y==f)continue;            if((x==pa&&y==pb)||(x==pb&&y==pa))continue;            dfs(y,x,d+edge[x][i].v);            fa[y][0]=x;fa[y][1]=edge[x][i].v;        }    }     void solve(int a,int b){//注意初始化!!!         memset(fa,0,sizeof(fa));        memset(dis,-1,sizeof(dis));        pa=a;pb=b;        mxdis=0;        dfs(a,-1,0);//找最大点         mxdis=0;dfs(dx,-1,0);//以dx为根建树 同时跟新dx-->变成另外一个端点         mxdis=0;fa[dx][0]=-1;dfs(dx,-1,0);         cdis=oo;         FOR(i,0,n){            if(dis[i]==-1)continue;            chk_mi(cdis,dis[i]);        }    }}A,B,C; int main(){    cin>>n;    FOR(i,1,n){        int a,b,c;        scanf("%d %d %d",&a,&b,&c);        edge[a].push_back((node){b,c});        edge[b].push_back((node){a,c});    }    A.solve(0,-1);    int x=A.dx,ans=A.mxdis;    while(A.fa[x][0]!=-1){        int y=A.fa[x][0];        B.solve(x,y);        C.solve(y,x);        chk_mi(ans,max(max(B.mxdis,C.mxdis),B.cdis+C.cdis+A.fa[x][1]));        x=y;    }    printf("%d\n",ans);    return 0;}
阅读全文
2 0