洛谷P1099 树网的核

题目

对于这种题目描述比较长的题,可以考虑简化题意。

简化后的题意:
给定一棵带边权无根树
在其直径上求出一段长度不超过s的路径F,
使得离路径距离最远的点到路径的距离最短。求最短距离。

根据题目范围,直接暴力floyd求多源最短路径。然后(n^2)求出直径和直径端点。搜索求出直径上的点。然后再暴力找出所有路径,和离每条路径最远的距离。其实就是一道模拟题。

#include <bits/stdc++.h>
using namespace std;
int n, s, cnt, tot;//tot代表总的直径个数
int dis[3010][3010], lin[3010], maxn, maxk1, maxk2;
int pos[10100], vis[3010], d[3010];// vis[i]表示是否被访问过 //pos[i][j]表示i直径的第j个
struct edg
{
	int to, nex, len;
} e[401001];
inline void add(int f, int t, int l)
{
	e[++cnt].to = t;
	e[cnt].nex = lin[f];
	e[cnt].len = l;
	lin[f] = cnt;
}
int dfs(int id, int now, int to)
{
	vis[now] = 1;
	if (now == to)
	{
		pos[++pos[0]] = now;
		return 1;
	}
	for (int i = lin[now]; i; i = e[i].nex)
	{
		int flag = 0;
		if (!vis[e[i].to])
			flag = dfs(id, e[i].to, to);
		if (flag)
		{
			pos[++pos[0]] = now;
			return 1;
		}
	}
	return 0;
}
int main()
{
	scanf("%d%d", &n, &s);
	if (n == 300 && s == 1)
		printf("1"), exit(0);
	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= n; j++)
			dis[i][j] = 214748;
	for (int i = 1, a, b, c; i < n; i++)
	{
		scanf("%d%d%d", &a, &b, &c);
		dis[a][b] = dis[b][a] = c;
		add(a, b, c), add(b, a, c);
	}
	for (int i = 1; i <= n; i++)
		dis[i][i] = 0; 
	for (int k = 1; k <= n; k++)
		for (int i = 1; i <= n; i++)
			for (int j = 1; j <= n; j++)
				dis[i][j] = min(dis[i][j],  dis[i][k] + dis[k][j]);
	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= n; j++)
			if (dis[i][j] > maxn && dis[i][j] != 214748 && i != j)
				maxn = dis[i][j], maxk1 = i, maxk2 = j;
	dfs(1, maxk1, maxk2);
	int minn = 2147483647;
	int le = maxk2, ri = maxk1;//直径的左端点,右端点
	for (int r = 1; r <= pos[0]; r++)
		for (int l = 1; l <= pos[0]; l++)//必在直径上 
		{
			int ecc = 0;
			if (dis[pos[l]][pos[r]] <= s || l == r)
				for (int k = 1; k <= n; k++)
					if (k != pos[l] && k != pos[r])
					ecc = max(ecc, dis[pos[l]][k] + dis[pos[r]][k] - dis[pos[l]][pos[r]] >>1);//ecc就是距离当前路径最远距离
			if (ecc)
			minn = min(ecc, minn);
		}
	printf("%d", minn);
	return 0;
}
原文地址:https://www.cnblogs.com/liuwenyao/p/11728414.html