您的位置:首页 > 其它

【bzoj1912】[Apio2010]patrol 巡逻

2017-04-12 16:15 267 查看
题目链接

Description



Input

第一行包含两个整数 n, K(1 ≤ K ≤ 2)。接下来 n – 1行,每行两个整数 a, b, 表示村庄a与b之间有一条道路(1 ≤ a, b ≤ n)。

Output

输出一个整数,表示新建了K 条道路后能达到的最小巡逻距离。

Sample Input

8 1

1 2

3 1

3 4

5 3

7 5

8 5

5 6

Sample Output

11

HINT

10%的数据中,n ≤ 1000, K = 1;

30%的数据中,K = 1;

80%的数据中,每个村庄相邻的村庄数不超过 25;

90%的数据中,每个村庄相邻的村庄数不超过 150;

100%的数据中,3 ≤ n ≤ 100,000, 1 ≤ K ≤ 2。

题解

没有多余的路可以连的话答案就是(n−1)×2

有一条路的话显然把最长链的两端连起来比较划算。最长链为cnt的话可以减少cnt−1。

如果还有一条路呢,那么我们就是找另外一条最长链,这个第二条最长链可以与第一条有重复的边,但是如果重复一条边的话就会少减少2,这样可以吧第一次最长链的边全部赋值为-1然后直接求解就好了。最长链用树形DP求。

#include<bits/stdc++.h>
using namespace std;

inline int read(){
int x = 0, f = 1; char c = getchar();
while(!isdigit(c)) { if(c == '-') f = -1; c = getchar(); }
while(isdigit(c)) { x = x * 10 + c - '0'; c = getchar(); }
return x * f;
}

const int N = 100000 + 10, M = 200000 + 10;
int to[M], nxt[M], val[M], hd
, c1
, c2
, tot = 1;
int n, k, ans, mxp, cnt;

inline void insert(int u, int v){
to[++tot] = v; nxt[tot] = hd[u]; hd[u] = tot; val[tot] = 1;
to[++tot] = u; nxt[tot] = hd[v]; hd[v] = tot; val[tot] = 1;
}
void init(){
n = read(), k = read();
for(int i = 1; i < n; i++) insert(read(), read());
}

int dfs(int u, int fa){
int mx1 = 0, mx2 = 0;
for(int i = hd[u]; i; i = nxt[i]){
int v = to[i];
if(v != fa){
int tmp = val[i] + dfs(v, u);
if(tmp > mx1) mx2 = mx1, mx1 = tmp, c2[u] = c1[u], c1[u] = i;
else if(tmp > mx2) mx2 = tmp, c2[u] = i;
}
}
if(mx1 + mx2 > cnt) cnt = mx1 + mx2, mxp = u;
return mx1;
}

void work(){
ans = (n - 1) * 2;
dfs(1, 0); ans -= cnt - 1;
if(k == 2){
for(int i = c1[mxp]; i; i = c1[to[i]]) val[i] = val[i^1] = -1;
for(int i = c2[mxp]; i; i = c1[to[i]]) val[i] = val[i^1] = -1;
cnt = 0;
dfs(1, 0); ans -= cnt - 1;
}
printf("%d\n", ans);
}

int main(){
init();
work();
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: