您的位置:首页 > 其它

bzoj 1912: [Apio2010]patrol 巡逻

2016-05-03 14:55 323 查看

1912: [Apio2010]patrol 巡逻

Time Limit: 4 Sec Memory Limit: 64 MB

Submit: 1007 Solved: 549

[Submit][Status][Discuss]

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。

Source



[Submit][Status][Discuss]

题解:

先说明一个定义: 树的直径是一棵树上最长的一条路径,从树上任意一个点dfs出离他最远的一个点,再从这个点dfs出离他最远的点,两次dfs出的点之间的路径就是树上最长的链,即最长的一条路径。

k==1 因为要使走的重复的路尽可能的短,所以我们在添加一条边的时候就要保证形成的环中的边尽可能的多,也就是求树上的最长链。ans=2(n-1)-len1+1

k==2 这时候需要在1的基础上再求最长链,因为如果再形成的环与第一个环有重叠的话,那么重叠的部分还是会走两次,所以把第一遍走过的路径付成-1,再求树的直径即可。ans=2(n-1)-len1+1-len2+1

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define N 200003
using namespace std;
int n,k;
int point
,next
,v
,c
,tot=-1,ans,ansx;
int last
,len1,len2;
void add(int x,int y,int z)
{
tot++; next[tot]=point[x]; point[x]=tot; v[tot]=y; c[tot]=z;
tot++; next[tot]=point[y]; point[y]=tot; v[tot]=x; c[tot]=z;
}
void dfs(int x,int fa,int dis,int num)
{
if (dis>ans)
{
ans=dis,ansx=x;
}
for (int i=point[x];i!=-1;i=next[i])
if (fa!=v[i])
{
last[v[i]]=i;
dfs(v[i],x,dis+c[i],i);
}
}
void change(int s,int t)
{
int now=t;
while (now!=s)
{
c[last[now]]=-1;
c[last[now]^1]=-1;
now=v[last[now]^1];
}
}
int dp(int x,int fa)
{
int first=0; int second=0;
for (int i=point[x];i!=-1;i=next[i])
if (v[i]!=fa)
{
int t=c[i]+dp(v[i],x);
if (t>first)
{
second=first; first=t;
}
else
if (t>second)
second=t;
}
if (first+second>ans)
ans=first+second;
return first;
}
int main()
{
scanf("%d%d",&n,&k);
tot=-1;
memset(point,-1,sizeof(point));
memset(next,-1,sizeof(next));
for (int i=1;i<n;i++)
{
int x,y; scanf("%d%d",&x,&y);
add(x,y,1);
}
dfs(1,0,0,0);
int head=ansx;
ans=0;
dfs(ansx,0,0,0);
int tail=ansx;
len1=ans;
change(head,tail);
if (k==1)
{
printf("%d\n",2*(n-1)-ans+1);
return 0;
}
ans=0;
dp(1,0);
printf("%d\n",2*(n-1)-len1-ans+2);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: