您的位置:首页 > 其它

2017百度之星初赛B-1002(HDU-6115)

2017-08-16 09:33 337 查看
一、思路

这题“看似”比较难搞的一点是,一个节点上有多个办公室,这怎么求?其他的,求树中任意两个节点的距离(注意:没有最远或最最进这一说法,因为树上任意两个节点之间有且仅有一条路径。不然就有回路了,对吧。)都不是特别难的问题。

(1)如何找到任意两个公司之间的最短距离?没有很好的办法,只能暴力。记录每个公司的每个办公室所在节点,求指定两个公司A和B的最短距离时,枚举公司A的所有办公室所在节点,再枚举公司B的所有办公室所在节点,求出被枚举的节点之间的距离,然后,取最小的那一个输出。

(2)求树中任意两个节点的距离?我一开始用的是Tarjan求LCA的算法,然后,交上去TLE了两发。后来换了一种策略,记录每个节点的深度、它的父节点以及它到父节点之间的距离。求任意两个点的LCA的时候,采用谁深度大谁先上移的方法,然后移动过程中记录移动了多少距离,当两个点移动到一个点时,这个点就是他们的LCA,返回记录的距离即可。这样,可以避免求子节点到根节点的距离(即麻烦又要多写很多不必要的代码)。另外一点,要不要先求出树的重心来优化时间复杂度,我用第二种策略提交的第一份AC的代码,求了树重心,耗时:8595MS;后来直接把求重心的代码去掉,直接把1号节点当总根节点,耗时:8782MS,差不多。所以,我下面贴的代码就没求树的重心了,这样代码也简洁了好多,关键函数就只有一个:找到给定两个节点的LCA并返回它们之间的距离。

二、代码
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
using namespace std;
const int INF = 0x3fff3fff;
const int MAXN = 100010;
typedef struct {
int to, wt, next;
} Edge;
Edge tree[MAXN * 2];
int head[MAXN], cnt;
int n, m, q;
/**office[i][j]:公司i的第j个办公室所在节点。*/
vector<int> office[MAXN];

void add(int from, int to, int wt) {
tree[cnt].to = to;
tree[cnt].wt = wt;
tree[cnt].next = head[from];
head[from] = cnt++;
}

void init() {
memset(head, -1, sizeof(head));
cnt = 0;
for(int i = 0; i < MAXN; ++i)office[i].clear();
}

/** deep[i]:i节点的深度。
f[i]:i节点的父节点。
len2f[i]:i节点到父节点的长度。
*/
int deep[MAXN], f[MAXN], len2f[MAXN];
/**
d:深度。总根(树的重心)节点的深度为0。
*/
void dfsDep(int root, int par, int d) {
deep[root] = d;
f[root] = par;
for(int i = head[root], to = -1; i != -1; i = tree[i].next) {
to = tree[i].to;
if(to != par) {
len2f[to] = tree[i].wt;
dfsDep(to, root, d + 1);
}
}
}

int getDis(int a, int b) {
int res = 0;
while(deep[a] < deep[b]) {
res += len2f[b];
b = f[b];
}
while(deep[a] > deep[b]) {
res += len2f[a];
a = f[a];
}
while(a != b) {
res += len2f[a] + len2f[b];
a = f[a];
b = f[b];
}
return res;
}

int main() {
#ifndef ONLINE_JUDGE
freopen("input.txt", "r", stdin);
#endif // ONLINE_JUDGE
int t, a, b, c;
scanf("%d", &t);
while(t--) {
init();
scanf("%d%d", &n, &m);
for(int i = 1; i < n; ++i) {
scanf("%d%d%d", &a, &b, &c);
add(a, b, c);
add(b, a, c);
}
for(int i = 1; i <= m; ++i) {
scanf("%d", &a);
for(int k = 0; k < a; ++k) {
scanf("%d", &b);
office[i].push_back(b);
}
}

dfsDep(1, -1, 0);

scanf("%d", &q);
for(int i = 1; i <= q; ++i) {
scanf("%d%d", &a, &b);
c = INF;
for(int j = 0, asz = office[a].size(); j < asz; ++j) {
for(int k = 0, bsz = office[b].size(); k < bsz; ++k) {
c = min(c, getDis(office[a][j], office[b][k]));
if(c == 0) {j = asz; break;}
}
}
printf("%d\n", c);
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: