您的位置:首页 > 其它

hdu - 4607 - Park Visit

2013-07-24 20:02 323 查看
题意:N个城市形成一棵树,相邻城市之间的距离是1,问游K个城市的最短路程是多少,共有M次询问(1 <= N, M <= 100000, 1 <= K <= N)。

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4607

——>>把这棵树拉直,得最长路(直径)共有maxd个城市,如果K <= maxd,只要一直向前走,路程为K - 1;如果K > maxd,贪心策略为最长路一定要从头走到尾,中间补上缺少的城市,每补一个,距离+2,结果是maxd - 1 + (K - maxd) * 2。

对于最长路(直径),可用无根树转有根树,第一次任选一点作根转一次,然后找出最深的叶子,第二次以这个最深的叶子为根转一次,树的层数就是最长路的长度。

#include <cstdio>
#include <vector>

using namespace std;

const int maxn = 100000 + 10;
vector<int> G[maxn];
int d[maxn];

void dfs(int u, int fa, int cur) //现在的点为u,其父结点为fa,从根到u的经过cur个点
{
d[u] = cur;
int cnt = G[u].size();
for(int i = 0; i < cnt; i++)
{
int v = G[u][i];
if(v != fa) dfs(v, u, cur+1);
}
}

int main()
{
int T, N, M, u, v, i, j, K;
scanf("%d", &T);
while(T--)
{
scanf("%d%d", &N, &M);
for(i = 1; i <= N; i++) G[i].clear();
for(i = 0; i < N-1; i++)
{
scanf("%d%d", &u, &v);
G[u].push_back(v);
G[v].push_back(u);
}
dfs(1, 0, 1); //第一次转有根树,找一个最长路的一端
j = 1;
for(i = 2; i <= N; i++) if(d[i] > d[j]) j = i;
dfs(j, 0, 1); //第二次转有根树,找最长路
j = 1;
for(i = 2; i <= N; i++) if(d[i] > d[j]) j = i;
int maxd = d[j], ret;
for(i = 0; i < M; i++)
{
scanf("%d", &K);
if(K <= maxd) ret = K - 1;
else ret = maxd - 1 + (K - maxd) * 2;
printf("%d\n", ret);
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: