POJ 1985. Cow Marathon

链接

http://poj.org/problem?id=1985

题意

求边权为正的树形图的直径(树上最长链)

思路一

两次 BFS(无法处理负边权)

随便选一个点 $p$,BFS 求出离点 $p$ 最远的点 $q$

再从点 $q$ 出发,BFS 求出离点 $q$ 最远的点 $r$

$q$ 到 $r$ 的距离就是树的直径

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#include<iostream>
#include<cstring>
#include<queue>
using namespace std;
const int N=1e5+5;
int n,m;
int cnt,to[N*2],val[N*2],nxt[N*2],head[N];
bool st[N];
int dist[N];
pair<int,int>mx;
void addedge(int u,int v,int w) {
cnt++;
to[cnt]=v;
val[cnt]=w;
nxt[cnt]=head[u];
head[u]=cnt;
}
void bfs(int u) {
queue<int>q;
mx.first=0;
memset(st,false,sizeof st);
q.push(u);
dist[u]=0;
st[u]=true;
while(q.size()) {
u=q.front();
q.pop();
for(int i=head[u];i;i=nxt[i]) {
int v=to[i],w=val[i];
if(st[v]) continue;
st[v]=true;
dist[v]=dist[u]+w;
if(dist[v]>mx.first) mx=make_pair(dist[v],v);
q.push(v);
}
}
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cin>>n>>m;
for(int i=1;i<=m;i++) {
int u,v,w;
char c;
cin>>u>>v>>w>>c;
addedge(u,v,w);
addedge(v,u,w);
}
bfs(1);
bfs(mx.second);
cout<<mx.first<<endl;
return 0;
}

思路二

树形 DP

首先任选一点为根,记为 $root$ 并记 $dp[x]$ 为以 $x$ 为起点与其朝下所有节点的路径最大值,进行一次树形 DP:

$dp[i]=\max \limits_{j \in son(i)}(dp[i],w[i][j]+dp[j])$

我们可以发现树的直径其实是以某一点为起点的路径长度的最大值与次大值和,且这两条路径没有重复边,因此我们在进行树形 DP从下到上转移时对 $res$ 进行更新:

$res=\max \limits_{j \in son(i)}(res,dp[i]+dp[j]+w[i][j])$

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#include<iostream>
using namespace std;
const int N=1e5+5;
const int M=2e5+5;
int n,m;
int cnt,to[M],val[M],nxt[M],head[N];
bool st[N];
int dp[N],res;
void addedge(int u,int v,int w) {
cnt++;
to[cnt]=v;
val[cnt]=w;
nxt[cnt]=head[u];
head[u]=cnt;
}
void dfs(int u) {
st[u]=true;
for(int i=head[u];i;i=nxt[i]) {
int v=to[i],w=val[i];
if(st[v]) continue;
dfs(v);
res=max(res,dp[u]+dp[v]+w);
dp[u]=max(dp[u],dp[v]+w);
}
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cin>>n>>m;
for(int i=1;i<=m;i++) {
int u,v,w;
char c;
cin>>u>>v>>w>>c;
addedge(u,v,w);
addedge(v,u,w);
}
dfs(1);
cout<<res<<endl;
return 0;
}