HDU 3721 - Building Roads(DFS`树的直径)

题目:

http://acm.hdu.edu.cn/showproblem.php?pid=3721

题意:

n个点的有边权的树,移动一条边(即改变边的两个端点),使得树的直径最短。

思路:

移动的边在原树的直径上,移动后原树变成两棵子树,求出两棵子树的直径。

枚举子树直径上的点,决定移动边的两个端点,求出最小的距离。

AC.

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>

using namespace std;
const int inf = 0x3f3f3f3f;
const int maxn = 2505;

int tot, head[maxn];
struct Edge{
    int to, w, next;
}edge[maxn*2];
void init()
{
    tot = 0;
    memset(head, -1, sizeof(head));
}
void addedge(int u, int v, int w)
{
    edge[tot].to = v;
    edge[tot].w = w;
    edge[tot].next = head[u];
    head[u] = tot++;
}

int num[maxn];
int res, point;
void dfs(int u, int fa)
{
    for(int i = head[u]; ~i; i = edge[i].next) {
        int v = edge[i].to, w = edge[i].w;
        if(v == fa) continue;
        num[v] = num[u] + w;
        if(res < num[v]) {
            res = num[v];
            point = v;
        }
        dfs(v, u);
    }
}
struct Path{
    int to, id;
}path[maxn];

void dfs1(int u, int fa)
{
    for(int i = head[u]; ~i; i = edge[i].next) {
        int v = edge[i].to, w = edge[i].w;
        if(v == fa) continue;
        num[v] = num[u] + w;
        path[v].to = u; path[v].id = i;
        if(res < num[v]) {
            res = num[v];
            point = v;
        }
        dfs1(v, u);
    }
}

int now;
int smpath[maxn];
int nog1, nog2;

void dfsmall(int u, int fa)
{
    if(u == now) return;
    for(int i = head[u]; ~i; i = edge[i].next) {
        int v = edge[i].to, w = edge[i].w;
        if(nog1 == i || nog2 == i) continue;

        if(v == fa) continue;
        num[v] = num[u] + w;
        if(res < num[v]) {
            res = num[v];
            point = v;
        }
        dfsmall(v, u);
    }
}
void dfsmall2(int u, int fa)
{
    for(int i = head[u]; ~i; i = edge[i].next) {
        int v = edge[i].to, w = edge[i].w;
        if(nog1 == i || nog2 == i) continue;

        if(v == fa) continue;
        num[v] = num[u] + w;
        smpath[v] = u;
        if(res < num[v]) {
            res = num[v];
            point = v;
        }
        dfsmall2(v, u);
    }
}

void initdfs()
{
    res = 0;
    memset(num, 0, sizeof(num));
}
int main()
{
   // freopen("in", "r", stdin);
    int TT, ca = 1;
    scanf("%d", &TT);
    while(TT--) {
        int n;
        scanf("%d", &n);
        init();
        int u, v, w;
        for(int i = 1; i < n; ++i) {
            scanf("%d%d%d", &u, &v, &w);
            addedge(u, v, w);
            addedge(v, u, w);
        }

        memset(path, -1, sizeof(path));
        int S, T;
        initdfs();  dfs(1, 1);
        S = point;
        initdfs();  dfs1(S, S);
        T = point;

        //printf("%d, %d\n", S, T);

        int ans = inf, r;

        int s1, t1, s2, t2, p1, p2;
        for(int i = T; ~i; i = path[i].to) {

            int id = path[i].id;
            if(id == -1) break;
            int u = edge[id].to, v = edge[id^1].to;
            nog1 = id; nog2 = id^1;

            r = edge[id].w;

            memset(smpath, -1, sizeof(smpath));
            initdfs();  dfsmall(u, u);
            s1 = point;
            initdfs();  dfsmall2(s1, s1);
            t1 = point;
            int r1 = num[t1];

          //  printf("****(%d, %d) = %d\n", s1, t1, num[t1]);

            int tmp = inf;
            for(int j = t1; ~j; j = smpath[j]) {
                int cnt = max(num[t1]-num[j], num[j]);
                tmp = min(tmp, cnt);
            }
           // printf("half path = %d\n", tmp);
            r += tmp;

            memset(smpath, -1, sizeof(smpath));
            initdfs();  dfsmall(v, v);
            s2 = point;
            initdfs();  dfsmall2(s2, s2);
            t2 = point;
            int r2 = num[t2];

           // printf("****(%d, %d) = %d\n", s2, t2, num[t2]);

            tmp = inf;
            for(int j = t2; ~j; j = smpath[j]) {
                int cnt = max(num[t2]-num[j], num[j]);
                tmp = min(tmp, cnt);
            }
           // printf("half path = %d\n", tmp);
            r += tmp;

            //printf("(%d, %d) = %d\n\n", u, v, r);
            r = max(r, max(r1, r2));

            ans = min(ans, r);
        }
        printf("Case %d: %d\n", ca++, ans);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值