Hdu 2196

即求树上每点的最长路,先求出树的直径上的一点(dfs、bfs均可,寻找第一点我用的bfs),然后再从这点搜出树直径的另一点。可以证明每点的最长路是到这两点的距离之一(因为树是连通的,因为是树的直径,如果某点s到直径某点t的距离小于到另一点u的距离,那么u就可以代替t成为树的直径了。

本题恶心的是内存限制,一开始采用边表老是超内存,后来把数组改为short后还不行,根据树的性质(E=V-1)使用数组链表,结果length可以超过short又忘了把short改为int就彻底悲剧了。。T^T

#include <stdio.h>
#include <string.h>

#define _END    0x4f4f
int pass[20005], head[10005];
int v[20010], dis[20010], xdis;
int dp0[10005], dp1[16384], *dp;
int f, r;

void dfs(int n)
{
    int i, j;
    if (dp[n] > dp[xdis]) xdis = n;
    for(i=head[n]; i<_END; i = pass[i]) {
        if (dp[j = v[i]] == -1) {
            dp[j] = dp[n] + dis[i];
            dfs(j);
        }
    }
}

#define max(a,b) ((a)>(b) ? (a) : (b))

int main(void)
{
    int N;
    while(scanf("%d", &N) > 0) {
        int i, j, k;
        i = 0;
        memset(head, _END, sizeof(head));
        for(j=1; j<N; ++j) {
            int l;
            scanf("%d%d", &k, &l); --k;
            pass[i] = head[j], v[i] = k, dis[i] = l; head[j] = i++;
            pass[i] = head[k], v[i] = j, dis[i] = l; head[k] = i++;
        }
        memset(dp = dp0, -1, sizeof(int) * N);
        int mx;
        #define q dp1
        mx = dp[0] = q[f = 0] = 0, r = 1;
        while(f != r) {
            j = q[f];
            if (dp[j] > dp[mx]) mx = j;
            int l;
            for(k=head[j]; k<_END; k = pass[k]) {
                l = v[k];
                if (dp[l] == -1) {
                    dp[q[r] = l] = dp[j] + dis[k];
                    r = (r+1) & 16383;
                }
            }
            f = (f+1) & 16383;
        }
        #undef q
        memset(dp, -1, sizeof(int) * N);
        dp[mx] = 0;    dfs(xdis = mx);
        memset(dp = dp1, -1, sizeof(int) * N);
        dp[xdis] = 0; dfs(xdis);
        for(j=0; j<N; ++j)
            printf("%d
", max(dp0[j], dp1[j]));
    }
    return 0;
}
原文地址:https://www.cnblogs.com/e0e1e/p/hdu_2196.html