P1099 [NOIP 2007 提高组] 树网的核
链接
https://www.luogu.com.cn/problem/P1099
题目
思路
思路对的,有些地方想的不严谨,但是看评论区证了。 题目有提示:虽然核不唯一,但是最小偏心距唯一。所以想到先找直径,然后再遍历求解。
比如这张图来说,对于i,j两点很显然只要满足|dist[j]-dist[i]|<=s,就求max(树枝长度,首到i的距离,j到尾的距离)。
比如:如果dist(2,4)<s那么当前段的最小偏心距就是max(dist(1,2),dist(2,q),dist(3,p),dist(3,5));
解释一下代码:前半段是利用dfs找到直径两端端点;然后再找到直径间的路径;最后求min(max(all))
代码
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<algorithm>
#include<queue>
#include<cmath>
#include<map>
#include<string.h>
#include<limits.h>
#include<string>
#include<vector>
#define IOS ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
using namespace std;
#define int long long
const int N = 310;
struct edge { int to, val; edge() {}; edge(int t, int v) :to(t), val(v) {} };
vector<edge>e[N];
int dist[N];
int nex[N];
void dfs(int u, int fa, int d)
{
dist[u] = d;
for (edge i : e[u])
if (i.to != fa)dfs(i.to, u, i.val+d);
}
bool findWay(int st, int ed, int now, int fa)
{
if (now == ed)
return true;
for (edge i : e[now])
if (i.to != fa)
if (findWay(st, ed, i.to, now))
{
nex[now] = i.to;
return true;
}
return false;
}
int waying[N];
int cal(int now, int fa, int d)
{
int ans = d;
int delta = 0;
for (edge i : e[now])
{
if (i.to == fa)continue;
else if (e[i.to].size() == 1)delta=i.val;
else delta = max(delta, cal(i.to, now, i.val));
}
return ans+delta;
}
int getmax(int s, int t)
{
int ans = waying[s];
while (s != t)
{
s = nex[s];
ans = max(waying[s],ans);
}
return ans;
}
signed main()
{
int n, sway; cin >> n >> sway;
for (int i = 1; i < n; i++)
{
int st, ed, dis;
cin >> st >> ed >> dis;
e[st].push_back(edge(ed, dis)),
e[ed].push_back(edge(st, dis));
}
dfs(1, -1, 0);
int s = 1;
for (int i = 1; i <= n; i++)
if (dist[i] > dist[s])
s = i;
dfs(s, -1, 0);
int t = s;
for (int i = 1; i <= n; i++)
if (dist[i] > dist[t])
t = i;
//以上是求出两端端点
findWay(s, t, s, -1);
//以上是求出路径
int ptr = nex[s];
int fa = s;
while (ptr != t)
{
for (edge i : e[ptr])
{
if (i.to != fa and i.to != nex[ptr])
waying[ptr] = max(waying[ptr], cal(i.to, ptr, i.val));
}
fa = ptr;
ptr = nex[ptr];
}
//以上是求出该路径各个端点上的其他路径长度的**最大值**
int ans = LLONG_MAX;
int lef = s, rig = s;
while (rig != t)
{
while (rig!=t and 0-dist[lef] + dist [nex[rig]] <= sway)rig = nex[rig];
ans = min(ans, max(0-dist[s] + dist[lef], max(getmax(lef, rig), dist[t]-dist[rig])));
lef = nex[lef];
}
//以上是求答案,注意是s->t,lef->rig。
cout << ans;
return 0;
}