树的直径(题目)

A.POJ_2631

 1 #include<iostream>
 2 #include<cstring>
 3 #include<queue>
 4 #include<vector>
 5 using namespace std;
 6 const int maxn = 24000;
 7 int vis[maxn];//把走过的点进行标记
 8 int dis[maxn];//到达每个点所需要走的路径长度。
 9 
10 vector<pair<int, int> >A[maxn];
11 long long ans = 0;;
12 int point = 0;
13 void bfs(int x)
14 {
15     memset(vis, 0, sizeof(vis));
16     memset(dis, 0, sizeof(dis));
17     queue<int> que;
18     que.push(x);
19     vis[x] = 1;
20     while (!que.empty()){
21         int f = que.front();
22         que.pop();
23         if (dis[f] > ans){
24             ans = dis[f];
25             point = f;
26         }
27         pair<int, int> p;
28         for (int i = 0; i < A[f].size(); i++){ //开始搜索以f为起点的所有的pair
29             p = A[f][i];                 //这一行是不是更能证明A[x][y]这个二维数组指向的就是一个pair;
30             if (vis[p.first] == 0){          //如果这个点没有走过则接着走。
31                 vis[p.first] = 1;           //标记这个点。
32                 dis[p.first] = dis[f] + p.second;//p.first代表一条边的中点,p.second代表这条边的权值。
33                 que.push(p.first);
34             }
35         }
36 
37     }
38 }
39 int main()
40 {
41     int a, b, c;
42     while(cin >> a >> b >> c){
43         A[a].push_back(make_pair(b, c));
44         A[b].push_back(make_pair(a, c));//建图
45     }
46     bfs(1);
47     ans = 0;
48     bfs(point);//两次bfs求树的直径
49     cout << ans << endl;
50     return 0;
51 }

B.POJ_1849

 

 1 #include<iostream>
 2 #include<cstring>
 3 #include<queue>
 4 #include<vector>
 5 using namespace std;
 6 const int maxn = 24000;
 7 int vis[maxn];//把走过的点进行标记
 8 int dis[maxn];//到达每个点所需要走的路径长度。
 9 
10 vector<pair<int, int> >A[maxn];
11 long long ans = 0;;
12 int point = 0;
13 void bfs(int x)
14 {
15     memset(vis, 0, sizeof(vis));
16     memset(dis, 0, sizeof(dis));
17     queue<int> que;
18     que.push(x);
19     vis[x] = 1;
20     while (!que.empty()){
21         int f = que.front();
22         que.pop();
23         if (dis[f] > ans){
24             ans = dis[f];
25             point = f;
26         }
27         pair<int, int> p;
28         for (int i = 0; i < A[f].size(); i++){ //开始搜索以f为起点的所有的pair
29             p = A[f][i];                 //这一行是不是更能证明A[x][y]这个二维数组指向的就是一个pair;
30             if (vis[p.first] == 0){          //如果这个点没有走过则接着走。
31                 vis[p.first] = 1;           //标记这个点。
32                 dis[p.first] = dis[f] + p.second;//p.first代表一条边的中点,p.second代表这条边的权值。
33                 que.push(p.first);
34             }
35         }
36 
37     }
38 }
39 int main()
40 {
41     int m, n;
42     int a, b, c;
43     int sum = 0;
44     cin >> m >> n;
45     for (int i = 0; i < m - 1; i++) {
46         cin >> a >> b >> c;
47         A[a].push_back(make_pair(b, c));
48         A[b].push_back(make_pair(a, c));//建图
49         sum += c;
50     }
51     memset(dis, 0, sizeof(dis));
52     memset(vis, false, sizeof(vis));
53     bfs(1);
54     ans = 0;
55     bfs(point);//两次bfs求树的直径
56     cout << 2 * sum - ans << endl;
57     return 0;
58 }

C.找两个人开始相距最大距离除以2即为答案

 1 #include <iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<queue>
 6 #include<vector>
 7 #include <iomanip>
 8 
 9 using namespace std;
10 const int MAN = 10086;
11 
12 vector<int>p[MAN];
13 int dis[MAN];
14 int vis[MAN];
15 int n, m, k;
16 int ans;
17 
18 void dfs(int s, int num){
19     int len = p[s].size();
20     for (int i = 0; i < len; i++){
21         if (!vis[p[s][i]]){
22             vis[p[s][i]] = 1;
23             if (dis[p[s][i]] == 1)                
24                 ans = max(ans, num + 1);
25             dfs(p[s][i], num + 1);
26             vis[p[s][i]] = 0;
27         }
28     }
29 }
30 
31 int main(){
32     int N;
33     cin >> N;
34     while (N--){
35         memset(dis, 0, sizeof(dis));
36         memset(vis, 0, sizeof(vis));
37         cin >> n >> m;
38         for (int i = 0; i <= n; i++)
39             p[i].clear();
40         int s1 = 0, s2 = 0;
41         k = 0;
42         for (int i = 0; i < m; i++){
43             int temp;
44             cin >> temp;
45             if (!dis[temp])
46                 k++;
47             dis[temp] = 1;
48             s1 = temp;
49         }
50         m = k;
51         for (int i = 0; i < n - 1; i++){
52             int a, b;
53             cin >> a >> b;
54             p[a].push_back(b);
55             p[b].push_back(a);
56         }
57         if (m == 1){
58             cout << "0.00" << endl;
59             continue;
60         }
61         queue<int>q;
62         queue<int>d;
63         int temp = 1;
64         q.push(s1);
65         d.push(0);
66         vis[s1] = 1;
67         int maxlen = 0;
68         while (!q.empty()){
69             int s = q.front();
70             int num = d.front();
71             d.pop();
72             q.pop();
73             int len = p[s].size();
74             for (int i = 0; i < len; i++){
75                 if (!vis[p[s][i]]) {
76                     q.push(p[s][i]);
77                     d.push(num + 1);
78                     vis[p[s][i]] = 1;
79                     if (dis[p[s][i]] == 1){
80                         temp++;
81                         if (num + 1 > maxlen){
82                             maxlen = num + 1;
83                             s2 = p[s][i];
84                         }
85                         if (temp == m)
86                             break;
87                     }
88                 }
89             }
90         }
91         ans = 0;
92         memset(vis, 0, sizeof(vis));
93         vis[s2] = 1;
94         dfs(s2, 0);
95         ans /= 2;
96         double answer = ans;
97         cout << fixed << setprecision(2) << answer  << endl;
98     }
99 }

D.树的内核  floyd算法(超时)  考虑用树的直径

// 超时代码
//#include<iostream>
//#include<cstring>
//#include<algorithm>
//#define FOR(a,b,c) for(int a=(b);a<(c);a++)	//	利用宏定义函数简化代码
//
//using namespace std;
//
//const int maxn = 5000;
//const int INF = 1 << 30;
//int nodes[maxn], nodes_n;
//int det[maxn][maxn];
//int ans, n, S;
//
//int main() {
//	ios::sync_with_stdio(false);	// 提高iostream性能
//	cin >> n >> S;
//	FOR(i, 1, n + 1) 
//		FOR(j, 1, n + 1)
//			if (i != j) 
//				det[i][j] = INF;
//	int u, v, w;
//	FOR(i, 0, n - 1) {
//		cin >> u >> v >> w;
//		det[v][u] = det[u][v] = w;
//	}
//	// floyd	算法
//	FOR(k, 1, n + 1)
//		FOR(i, 1, n + 1)
//			FOR(j, 1, n + 1)
//				if (det[i][k] < INF && det[k][j] < INF)
//					det[i][j] = min(det[i][j], det[i][k] + det[k][j]);
//	int _max = 0, maxi, maxj;  //找直径 
//	FOR(i, 1, n + 1) FOR(j, 1, n + 1)
//		if (det[i][j]<INF && det[i][j]>_max) {
//			_max = det[i][j];
//			maxi = i; maxj = j;
//		}
//	ans = INF;
//	FOR(i, 1, n + 1) 
//		if (det[maxi][i] + det[maxj][i] == det[maxi][maxj])
//	FOR(j, 1, n + 1) 
//		if (det[maxi][j] + det[maxj][j] == det[maxi][maxj]) {
//		if (det[i][j] > S) 
//			continue;  //直径上 长度<=S 的一段 
//		int ecg = max(min(det[i][maxi], det[j][maxi]), min(det[maxj][i], det[maxj][j]));
//		ans = min(ans, ecg);
//	}
//	cout << ans << endl;
//	return 0;
//}

//正解

// 两个结论
//(1)对于树中的任意一点,距离其最远的点一定是树的直径的某一端点。
//(2)所有的直径是等价的,即任意一条所能求出的该最小偏心距相等。
#include<cstdio>
#include<cstring>
#include<iostream>
#include<vector>
#include<algorithm>

using namespace std;

inline const int get() {
	int x = 0, f = 1;
	char ch = getchar();
	while (ch > '9' || ch < '0'){ 
		if (ch == '-')
		f = -1; 
		ch = getchar();
	}
	while (ch >= '0'&&ch <= '9') { 
		x = x * 10 + ch - '0'; 
		ch = getchar();
	}
	return x * f;
}

const int N = 5e5 + 100;
int dis[N], f[N];
bool vis[N];
vector<pair<int, int> >det[N];

void dfs(int x) {
	for (int i = 0; i < det[x].size(); i++) {
		int nx = det[x][i].first;
		if (vis[nx] || nx == f[x])
			continue;
		f[nx] = x;
		dis[nx] = dis[x] + det[x][i].second;
		dfs(nx);
	}
}
int main() {
	int n = get(), s = get();
	for (int i = 1; i < n; i++) {
		int u = get(), v = get(), w = get();
		det[u].push_back(make_pair(v, w));
		det[v].push_back(make_pair(u, w));
	}
	int l = 1, l2 = 1;
	dis[l] = 0; dfs(l);
	memset(f, 0, sizeof f);
	for (int i = 1; i <= n; i++) 
		if (dis[i] > dis[l]) l = i;
	dis[l] = 0; dfs(l);
	for (int i = 1; i <= n; i++) 
		if (dis[i] > dis[l2]) 
			l2 = i;
	int ans = 0x7fffffff, j = l2;
	for (int i = l2; i; i = f[i]) {
		while (f[j] && dis[i] - dis[f[j]] <= s) 
			j = f[j];
		ans = min(ans, max(dis[j], dis[l2] - dis[i]));
	}
	for (int i = l2; i; i = f[i]) 
		vis[i] = 1;
	for (int i = l2; i; i = f[i]) 
		dis[i] = 0, dfs(i);
	for (int i = 1; i <= n; i++) 
		ans = max(ans, dis[i]);
	cout << ans << endl;
	return 0;
}
作者:LightAc
出处:https://www.cnblogs.com/lightac/
联系:
Email: dzz@stu.ouc.edu.cn
QQ: 1171613053
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接,否则保留追究法律责任的权利。
原文地址:https://www.cnblogs.com/lightac/p/10544087.html