poj1985 求树的直径
http://poj.org/problem?id=1985
当初在刘书看过树上最远对,但是依稀记得是dp,而直径是双dfs好像没关系。
今天终于搞懂了,是双dfs的dp
第一遍dfs产生树形图,f,g分别记录i点只考虑到子树内的叶子的最远距离,次远距离
第二遍dfs利用f和g计算出h,表示i点“上面”的子树内的叶子的最远距离,之所以次远也要是因为可能最远的在子树内不在“上面”。
这里有一个问题,dp是有阶段性的,怎么保证计算h的时候需要的数据都已经计算好了?dfs先dfs再更新,保证子点先算玩,dfs1先更新再dfs1,保证父点先算玩。
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<vector> using namespace std; #define maxn 40005 #define For(i,k,n) for(int i=k;i<=n;i++) #define ForD(i,k,n) for(int i=n;i>=k;i--) #define Lson (x<<1) #define Rson ((x<<1)+1) #define MEM(a) memset(a,0,sizeof(a)); #define NEG(a) memset(a,-1,sizeof(a)); #define FILL(a) memset(a,0x3f,sizeof(a)); #define fp freopen("in.txt","r",stdin) struct edge { int v, w; }; int N,M; int f[maxn],g[maxn],h[maxn],longest[maxn]; vector<edge>e[maxn]; void init() { For(i,1,N) e[i].clear(); NEG(f);NEG(g);NEG(h);NEG(longest); } int dfs(int root, int pre){ int est = 0, esti=-1, er=0; if(f[root]!=-1) return f[root]; if(e[root].empty()) { //printf("root=%d\n",root); return f[root] = 0; } for(int i=0;i<e[root].size();i++){ if(pre!=e[root][i].v){ if(dfs(e[root][i].v,root)+e[root][i].w>est){ est = f[e[root][i].v]+e[root][i].w; esti = i; } } } longest[root] = esti; for(int i=0;i<e[root].size();i++){ if(pre!=e[root][i].v){ if(f[e[root][i].v]+e[root][i].w>er&&i!=longest[root]){ er = f[e[root][i].v]+e[root][i].w; } } } g[root] = er; return f[root] = est; } void dfs1(int root, int pre){ for(int i=0;i<e[root].size();i++){ if(pre!=e[root][i].v){ if(i!=longest[root]){ h[e[root][i].v] = max(h[root],f[root])+e[root][i].w; } else{ h[e[root][i].v] = max(h[root],g[root])+e[root][i].w; } dfs1(e[root][i].v,root); } } } void solve() { For(i,1,N) { //printf("%d\n",i); if(f[i]==-1) { f[i]=dfs(i,-1); //printf("f[%d]=%d\n",i,f[i]); h[i]=0;dfs1(i,-1); //printf("h[%d]=%d\n",i,h[i]); } } int ans=0; For(i,1,N) ans=max(ans,max(f[i],h[i])); printf("%d\n",ans); } int main() { //fp; while(scanf("%d %d",&N,&M)==2) { init(); For(i,1,M) { int u,v,w; scanf("%d %d %d",&u,&v,&w); getchar();getchar();getchar(); e[u].push_back(edge{v,w}); e[v].push_back(edge{u,w}); //printf("u=%d v=%d\n",u,v); } solve(); } return 0; }