【HDU3721】枚举+最长路

题意:给你一颗n个节点n-1条边的树,每条边都有一个权值,现在让你任意移动一条边然后把这条边连接到任意两个点上,最后问你怎样移动才能使树上相距最远的两个点距离最小。

 

思路:先求出树的最长路,然后枚举移动最长路上的所有边,移走这条边后,原树必定分为不连接的两颗子树,分别求这两颗子树的最长路,然后分别找到两颗子树最长路上靠近中点的点,那么最长路有三种情况:假设这条边为 u -> v

1.u的左子树的直径;

2.v的右子树的直径;

3.u的左子树的直径上中点分割的最长路径 +  v的右子树的直径上中点分割的最长路径 + 边权

每枚举一条边,就取这三种情况的最大值;

需要注意的事:两棵子树的最长路,一定是以整棵树的最长路的两个端点为起始点的,因此只需要预处理出所有点到两个端点的距离,然后根据删除的最长路边求两颗子树中的最大值即可。

所以我们只需2次BFS就够了;

我感觉我的代码很简短:

#include 
#include 
#include 
#include 
using namespace std;
#define N 3000
int head[N],cnt;
void ini()
{
    memset(head,-1,sizeof(head));
    cnt=0;
}
struct Edge
{
    int next,w,to;
}e[N*2];
void Add_edge(int a, int b, int c)
{
    e[cnt].to=b;e[cnt].w=c;
    e[cnt].next=head[a];
    head[a]=cnt++;
}
int dis1[N],dis2[N],fa2[N],vis[N],fa1[N],max_dis,max_id;
void BFS(int root, int dis[], int fa[])
{
    max_dis=0;max_id=root;fa[root]=root;
    memset(vis,0,sizeof(vis));
    dis[root]=0;
    queue  Q;
    Q.push(root);
    while(!Q.empty())
    {
        int u=Q.front();Q.pop();
        vis[u]=1;
        for(int i = head[u]; i != -1; i = e[i].next)
        {
            int v=e[i].to;
            if(vis[v])continue;
            dis[v]=dis[u]+e[i].w;
            if(max_dis


你可能感兴趣的:(图论)