201503-4 网络延时 (本质是求树的最长路径)

参考博文:
<1>poj总结链接
<2> acwing 代码链接
<3> 数学证明

相关题目链接
ACWing
POJ:
CCF-CSP:

题目:

对于一颗n个结点的无根树,找到一条最长路径。(找到两个距离最远的点)

思路:

(树的重心问题)
先将无根树转换成有根树,即随意找一点i作为根节点,经过i的最长路就连接着两颗不同子树u和v的最深叶子节点的路径。

求解方法:

任意找一点i为根节点,找到距离该结点最远距离的点u。
再从u出发,寻找离u最远的节点v。u到v的距离即为树的最长路径。

动态规划三部曲

1)状态定义

dp[i] 表示以i为根节点的子树到叶节点的最大距离

2)状态转移方程

边权为1时:
dp[i] = max{dp[j] + 1}
边权不为1时:
dp[i] = max{dp[j] + w(i)}

(1)ACWing上的问题

类型:有边权

#include <iostream>
#include <cstring>
#include <vector>
using namespace std;

const int N = 10010;
int n;
int ans;
struct Node {
	int v, dis;
	Node(int _v, int _dis) {
		v = _v;
		dis = _dis;
	}
};
vector<Node> Adj[N];
int dfs(int u, int father) {
	//根据贪心理论,以u为根的最长路径必然由经过不同的子树的最长和次长
	int d1 = 0, d2 = 0;
	for (int i = 0; i < Adj[u].size(); i++) {
		int v = Adj[u][i].v;
		int dis = Adj[u][i].dis;
		if (v == father)
			continue;
		int d = dfs(v, u) + dis;  //u->v之前的距离
		//dist = max(dist, d);
		if (d >= d1) {
			d2 = d1;
			d1 = d;
		} else if (d > d2) {
			d2 = d;
		}
	}
	ans = max(ans, d1 + d2);
	//cout << d1 << endl;
	return d1;
}

int main() {
	cin >> n;
	int a, b, c;
	for (int i = 0; i < n - 1; i++) {
		cin >> a >> b >> c;
		Adj[a].push_back(Node(b, c));
		Adj[b].push_back(Node(a, c));
	}

	dfs(1, -1);
	cout << ans << endl;

	return 0;
}

(2) POJ上的问题

类型:有边权

#include <iostream>
#include <cstdlib>
#include <cstring>
#include <vector>
using namespace std;
const int N = 10010;
int n, m;

struct Node {
	int v, dis;
	Node(int _v, int _dis) {
		v = _v;
		dis = _dis;
	}
};
vector<Node> Adj[N];
int dis[N];
int vis[N];

void dfs(int u, int t) {
	dis[u] = t;
	for (int i = 0; i < Adj[u].size(); i++) {
		int v = Adj[u][i].v;
		if (vis[v] == false) {
			vis[v] = true;
			dfs(v, t + Adj[u][i].dis);
		}
	}
}

int main() {
	int u, v, w;
	int maxn = 0;
	while (cin >> u >> v >> w) {
		Adj[u].push_back(Node(v, w));
		Adj[v].push_back(Node(u, w));
		if (u > v) {
			maxn = max(maxn, u);
		} else {
			maxn = max(v, maxn);
		}
	}
	//cout << maxn << endl;
	memset(dis, 0, sizeof dis);
	fill(vis, vis + N, false);
	dfs(1, 0);
	int start = 0;
	int maxdis = 0;
	for (int i = 0; i <= maxn; i++) {
		if (dis[i] > maxdis) {
			start = i;
			maxdis = dis[i];
		}
	}

	memset(dis, 0, sizeof dis);
	fill(vis, vis + N, false);
	dfs(start, 0);
	maxdis = 0;
	for (int i = 0; i <= maxn; i++) {
		if (dis[i] > maxdis) {
			start = i;
			maxdis = dis[i];
		}
	}
	cout << maxdis << endl;
	return 0;
}

(3) CCF-CSP上的问题

类型:无边权

#include <iostream>
#include <vector>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 20010;
int dis[N]; // 用于存储最远距离
bool vis[N];
int n, m;
vector<int> Adj[N];

void dfs(int start, int t) {
	dis[start] = t;
	for (int i = 0; i < Adj[start].size(); i++) {
		if (vis[Adj[start][i]] == false) {
			vis[Adj[start][i]] = true;
			dfs(Adj[start][i], t + 1);
		}
	}
}


int main() {
	cin >> n >> m;
	int a;
	for (int i = 2; i <= n; i++) {
		cin >> a;
		Adj[i].push_back(a);
		Adj[a].push_back(i);
	}
	for (int i = n + 1; i <= n + m; i++) {
		cin >> a;
		Adj[a].push_back(i);
		Adj[i].push_back(a);
	}
	memset(dis, 0, sizeof dis);
	fill(vis, vis + N, false);
	int start = 0;
	int maxdis = 0;
	//寻找最远点u
	dfs(1, 0);
	for (int i = 1; i <= n + m; i++) {
		if (dis[i] > maxdis) {
			start = i;
			maxdis = dis[i];
		}
	}

	maxdis = 0;
	memset(dis, 0, sizeof dis);
	fill(vis, vis + N, false);
	dfs(start, 0);
	for (int i = 1; i <= n + m; i++) {
		if (dis[i] > maxdis) {
			maxdis = dis[i];
		}
	}
	cout << maxdis << endl;
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值