一些说在前面的默认设定:
x:当前节点
c:当前节点的儿子节点
f:当前节点的父亲节点
(x,y)x->y的路径
wx,yx->y的路径长度
Example 1
description:给定一个无向图G,求此图中任意两点之间路径的最短路的最大值。
情形一:普通图
对于每个节点都跑一遍
情形二:树形图
算法1:贪心
对于任意一个节点x,找到离其最远的点y,再从y找到离其最远的点z,
算法2:树形dp
设1为根,则该图变为有根树,记L[x]为以x为根的子树中的最长路。显然
分类讨论——两种路径
1. 不经过节点x的路径:
max L[c]
2. 经过节点x的路径:
设down[x]为x向下能走的最长路的长度,
L[x]为down[c]中的最大值和次大值之和(这里次大值的初始值为0)
Example 2
description:给定一个无向图G,求此图中从每个点开始的最长路。
分类讨论
第一步向下走:即
第一步向上走:设up[x]为以x为起点,第一步往上走能走的最长路的长度.
第一步从x走到了
第二步继续向上走:即up[f]
第二步向下走(notice:不能回到x):如果如果down[f] 不是由down[x] 更新得来,那么就是down[f],如果是的话,就是down2[f].
down2[x]=smax(down[c]+wc−>x)
down1v[x] 记录down[x]是由哪一个c转移过来的。
/*
ID:Agreement
PROG:HDU 2196 Computer
*/
// Invincible
#include <bits/stdc++.h>
#define rep( i , l , r ) for( int i = (l) ; i <= (r) ; ++i )
#define per( i , r , l ) for( int i = (r) ; i >= (l) ; --i )
#define erep( i , u ) for( int i = head[(u)] ; ~i ; i = e[i].nxt )
using namespace std;
const int maxn = 10000 + 5;
struct edge{
int v , w , nxt;
}e[maxn * 2];
int head[maxn] , _t;
inline void ins( int u , int v , int w ){
e[_t].v = v , e[_t].w = w , e[_t].nxt = head[u] , head[u] = _t; _t++;
e[_t].v = u , e[_t].w = w , e[_t].nxt = head[v] , head[v] = _t; _t++;
}
int down[maxn] , down2[maxn] , down1v[maxn] , up[maxn];
void dfs1( int u , int f ){
erep( i , u ){
int v = e[i].v;
if( v == f ) continue;
dfs1( v , u );
if( down[u] < down[v] + e[i].w ){
down2[u] = down[u];
down[u] = down[v] + e[i].w;
down1v[u] = v;
}else{
down2[u] = max( down2[u] , down[v] + e[i].w );
}
}
}
void dfs2( int u , int f ){
erep( i , u ){
int v = e[i].v;
if( v == f ) continue;
if( down1v[u] != v ) up[v] = max( up[u] , down[u] ) + e[i].w;
else up[v] = max( up[u] , down2[u] ) + e[i].w;
dfs2( v , u );
}
}
void clear(){
_t = 0;
memset( head , 0xff , sizeof head );
memset( up , 0 , sizeof up );
memset( down , 0 , sizeof down );
memset( down2 , 0 , sizeof down2 );
}
int main(){
int N = 0 , u , v , w;
while( scanf("%d" , &N) != EOF && N ){
clear();
rep( i , 2 , N ){
scanf("%d %d" , &v , &w);
ins( i , v , w );
}
dfs1( 1 , -1 );
dfs2( 1 , -1 );
rep( i , 1 , N )
printf( "%d\n" , max( down[i] , up[i] ) );
}
return 0;
}
Example 3
SPOJ MTREE
在一棵树上,求出所有路径边权积的和取模。
题解:由于本题无特殊限制,将任意一点设为根,这样任意一条路径由一到两条儿子->祖先这样的路径组成,如果两条路径有重叠可以乘法分配律提取公因数,转化到树上即是记录每一个子树内的答案以及包含子树边路径的答案。
Example 4
SPOJ GS
给定一棵树,每个点都有给定概率往其相邻点走,问从某一点到另一点期望走多少步。
没有找到原题,不知道是否可以绕环走,这样有可能无法出答案,所以暂时不写题解了。