Hdu 2196 - Computer
即求树上每点的最长路,先求出树的直径上的一点(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\n", max(dp0[j], dp1[j])); } return 0; }
This article is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.
本文采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。