↓ Skip to main content
  1. Posts/

hdu 4607 Park Visit (树的直径,推公式)

·748 words·2 mins
Note: This article is available in Chinese only. 本文暂无英文版本。 View original

hdu4607题目链接 题意:给出一棵树。。。边权都为1. m个查询。。每个查询给一个k,表示只访问k个点。。。问每次的最小路径和是多少。。。 思路:我们发现。。会使路径和变大的一个不利因素是折返。。也就是访问某景点后。。必须要回去才能继续前进。。这样的距离是2倍。。那为了使得路径和尽可能小。。我们就尽量不要访问这样的点。。。而不是这样的点一定在直径上。。。以及我们还发现。。。不在直径上的点。。 。。不管深度如何(深度的意思是说,与和该点最近的直径上的点的距离),距离的贡献是一样的。。都是2倍。。所以我们可以推出一个公式。。。如果树的直径是d,那么k<=d+1的时候,答案为k-1,否则答案为d+(k-d-1)*2。。。

因为bfs的时候忘记标记起点WA了一发蠢哭。。。。2A

代码实现
  1/* ***********************************************
  2Author :111qqz
  3Created Time :2016年07月13日 星期三 14时33分29秒
  4File Name :code/poj/4607.cpp
  5 ************************************************ */
  6
  7#include <cstdio>
  8#include <cstring>
  9#include <iostream>
 10#include <algorithm>
 11#include <vector>
 12#include <queue>
 13#include <set>
 14#include <map>
 15#include <string>
 16#include <cmath>
 17#include <cstdlib>
 18#include <ctime>
 19#define fst first
 20#define sec second
 21#define lson l,m,rt<<1
 22#define rson m+1,r,rt<<1|1
 23#define ms(a,x) memset(a,x,sizeof(a))
 24typedef long long LL;
 25#define pi pair < int ,int >
 26#define MP make_pair
 27
 28using namespace std;
 29const double eps = 1E-8;
 30const int dx4[4]={1,0,0,-1};
 31const int dy4[4]={0,-1,1,0};
 32const int inf = 0x3f3f3f3f;
 33const int N=1E5+7;
 34vector< int >edge[N];
 35int n,m;
 36int d[N];
 37int lst,beg;
 38bool vis[N];
 39
 40void bfs( int s)
 41{
 42    ms(d,0);
 43    ms(vis,false);
 44
 45    queue<int>q;
 46    q.push(s);
 47    vis[s] = true;
 48
 49    while(!q.empty())
 50    {
 51	int u = q.front();
 52	q.pop();
 53	//	cout<<"u:"<<u<<endl;
 54	int siz = edge[u].size();
 55	for ( int i = 0 ; i <siz ; i++)
 56	{
 57	    int v = edge[u][i];
 58	    if (vis[v]) continue;
 59	    d[v] = d[u] + 1;
 60	    vis[v] = true;
 61	    q.push(v);
 62	}
 63    }
 64}
 65int main()
 66{
 67#ifndef  ONLINE_JUDGE
 68    freopen("code/in.txt","r",stdin);
 69#endif
 70    int T;
 71    cin>>T;
 72    while (T--)
 73    {
 74	scanf("%d%d",&n,&m);
 75	for ( int i = 1 ; i <= n ; i++) edge[i].clear();
 76	for ( int i = 1 ; i <= n-1 ; i++)
 77	{
 78	    int u,v;
 79	    scanf("%d%d",&u,&v);
 80	    edge[u].push_back(v);
 81	    edge[v].push_back(u);
 82	}
 83
 84	bfs(1);
 85	int mx = 0;
 86	for ( int i = 1 ; i <= n ; i++)
 87	{
 88	    if (d[i]>mx)
 89	    {
 90		mx = d[i];
 91		lst = i;
 92	    }
 93	}
 94	//	    cout<<endl;
 95	bfs(lst);
 96	mx = 0 ;
 97	for ( int i = 1 ; i <= n ; i++)
 98	{
 99	    if (d[i]>mx)
100	    {
101		mx = d[i];
102		beg = i;
103	    }
104	}
105	//	    cout<<"beg:"<<beg<<" lst:"<<lst<<endl;
106	//	    cout<<"mx:"<<mx<<endl;
107	while (m--)
108	{
109	    int x;
110	    int ans;
111	    scanf("%d",&x);
112	    if (x<=mx+1)
113	    {
114		ans = x-1;
115	    }
116	    else
117	    {
118		ans = mx + (x-mx-1)*2;
119	    }
120	    printf("%d\n",ans);
121	}
122
123    }
124
125#ifndef ONLINE_JUDGE
126    fclose(stdin);
127#endif
128    return 0;
129}

Related

poj 3310 Caterpillar (树的直径+并查集判环+dfs判断连通性)

poj 3310 题目链接 题意:给出一个无向图,问是否满足:连通,并且无环,并且能找到一条路径,图中所有的顶点要么在这条路径上,要么与这条路径上的顶点相邻。 思路:一个一个来。连通的话任意起点开始跑一遍 dfs?开一个 bool 数组标记走过的点,最后扫一遍,看是否有点没走过。

hdu 4514 湫湫系列故事——设计风景线 (无向图并查集判环+非联通图的最长路径)

·897 words·2 mins
hdu 4514 题意:给出一个无向图,问是否有环,有的话输出 YES。如果没有环的话,输出最长路径。 思路:无向图判环用并查集就好。关于最长路径这里,一开始以为就是树的直径。 但是需要注意的是,题目并没有保证图一定是联通的,所以 gg 了。

hdu 2196 Computer (树的直径||树形dp)

·1552 words·4 mins
hdu 2196 题意:给出一棵树,求距离每个点的最远距离是多少。 思路:最远距离什么的,能想到树的直径,但是有什么关系呢?我们在求树的直径的时候,直径的两个端点是可以知道的。如果再从两个端点分别做两次 bfs,每个点取两个距离的较大值就是答案。。?

poj 2631 Roads in the North (树的直径)

·380 words·1 min
poj2631 题意:一棵树中求两个点的最远距离。。。 思路:就是求树的直径。。。裸体。。。。1A 代码实现 1/* *********************************************** 2Author :111qqz 3Created Time :2016年07月12日 星期二 13时03分39秒 4File Name :code/poj/2631.cpp 5************************************************ */ 6 7#include <cstdio> 8#include <cstring> 9#include <iostream> 10#include <algorithm> 11#include <vector> 12#include <queue> 13#include <set> 14#include <map> 15#include <string> 16#include <cmath> 17#include <cstdlib> 18#include <ctime> 19#define fst first 20#define sec second 21#define lson l,m,rt<<1 22#define rson m+1,r,rt<<1|1 23#define ms(a,x) memset(a,x,sizeof(a)) 24typedef long long LL; 25#define pi pair < int ,int > 26#define MP make_pair 27 28using namespace std; 29const double eps = 1E-8; 30const int dx4[4]={1,0,0,-1}; 31const int dy4[4]={0,-1,1,0}; 32const int inf = 0x3f3f3f3f; 33const int N=1E4+7; 34int n,m; 35vector < pi> edge[N]; 36int lst; 37int ans; 38int d[N]; 39bool vis[N]; 40 41 42void bfs( int s) 43{ 44 ms(d,0x3f); 45 ms(vis,false); 46 queue<int>q; 47 q.push(s); 48 vis[s] = true; 49 d[s] = 0 ; 50 51 while (!q.empty()) 52 { 53 int u = q.front() ; q.pop(); 54 lst = u ; 55// cout<<"u:"<<u<<endl; 56 int siz = edge[u].size(); 57 58 for ( int i = 0 ; i < siz ; i++) 59 { 60 int v = edge[u][i].fst; 61 if (vis[v]) continue; 62 vis[v] = true; 63 d[v] = d[u] + edge[u][i].sec; 64 ans = max(d[v],ans); 65 q.push(v); 66 } 67 } 68 69 int mx = 0; 70 for ( int i = 1 ; i <= n ; i++) 71 { 72// cout<<"i:"<<i<<" d[i]:"<<d[i]<<endl; 73 if (d[i]>mx) 74 { 75 mx = d[i]; 76 lst = i ; 77 } 78 } 79 80} 81int main() 82{ 83 #ifndef ONLINE_JUDGE 84 freopen("code/in.txt","r",stdin); 85 #endif 86 87 int u,v,w; 88 m = 0; 89 n = 0; 90 while (scanf("%d%d%d",&u,&v,&w)!=EOF) 91 { 92 edge[u].push_back(make_pair(v,w)); 93 edge[v].push_back(make_pair(u,w)); 94 m++; 95 n = max(n,u); 96 n = max(n,v); 97 } 98 ans = inf; 99 bfs(1); 100 ans = 0; 101// cout<<"lst:"<<lst<<endl; 102 bfs(lst); 103 cout<<ans<<endl; 104 105 #ifndef ONLINE_JUDGE 106 fclose(stdin); 107 #endif 108 return 0; 109}

poj 1985 Cow Marathon (树的直径模板题)

·728 words·2 mins
poj1985 题意:求树上两点的最长距离。。。也就是传说中的树的直径。。。 思路: 两遍BFS :先任选一个起点BFS找到最长路的终点,再从终点进行BFS,则第二次BFS找到的最长路即为树的直径; 原理: 设起点为u,第一次BFS找到的终点v一定是树的直径的一个端点 证明: 1) 如果u 是直径上的点,则v显然是直径的终点(因为如果v不是的话,则必定存在另一个点w使得u到w的距离更长,则于BFS找到了v矛盾) 2) 如果u不是直径上的点,则u到v必然于树的直径相交(反证),那么交点到v 必然就是直径的后半段了 所以v一定是直径的一个端点,所以从v进行BFS得到的一定是直径长度