码迷,mamicode.com
首页 > Windows程序 > 详细

【BZOJ 1912】 [Apio2010]patrol 巡逻

时间:2015-05-07 08:49:37      阅读:150      评论:0      收藏:0      [点我收藏+]

标签:bzoj   oi   思路题   树的直径   

1912: [Apio2010]patrol 巡逻

Time Limit: 4 Sec Memory Limit: 64 MB
Submit: 669 Solved: 380
[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。

树的直径。

①如果k=1,显然是要求树的直径(因为在环上的边只需要走一次)。

②如果k=2,我们需要求加入两条边组成的环最大。

换个角度来看,相当于第一次找到直径之后进行第二次寻找,如果第二次找直径包含第一次找到的边,那么这条边对总答案的贡献为?1

所以只要在第一次直径之后把直径上的边权置为?1,然后再找一次直径即可。

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <cstdio>
#define M 200005
#define inf 0x3f3f3f3f
using namespace std;
int from,to,h[M],d[M],ans2,p[M],f[M],k,n,tot;
struct edge
{
    int y,ne,v;
}e[M];
void Addedge(int x,int y)
{
    e[++tot].y=y;
    e[tot].ne=h[x];
    e[tot].v=1;
    h[x]=tot;
}
void dfs(int x,int fa)
{
    for (int i=h[x];i;i=e[i].ne)
    {
        int y=e[i].y;
        if (y==fa) continue;
        d[y]=d[x]+e[i].v;
        p[y]=i;
        f[y]=x;
        dfs(y,x);
    }
}
int Getdiameter()
{   
    d[1]=0;
    dfs(1,0);
    from=0,to=0;
    for (int i=1;i<=n;i++)
        if (d[from]<d[i]) from=i;
    d[from]=0;
    p[from]=f[from]=0;
    dfs(from,0);
    for (int i=1;i<=n;i++)
        if (d[to]<d[i]) to=i;
    return d[to]-1;
}
void dfs2(int x,int fa)
{
    int m1=-inf,m2=-inf;
    for (int i=h[x];i;i=e[i].ne)
    {
        int y=e[i].y;
        if (y==fa) continue;
        dfs2(y,x);
        d[y]+=e[i].v;
        d[x]=max(d[x],d[y]);
        if (d[y]>m1) m2=m1,m1=d[y];
        else if (d[y]>m2) m2=d[y];
    }
    if (m1==-inf&&m2==-inf)
        d[x]=0;
    ans2=max(ans2,m1+m2-1);
}
int main()
{
    tot=1;
    scanf("%d%d",&n,&k);
    for (int i=1;i<n;i++)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        Addedge(x,y),Addedge(y,x);
    }
    int ans=2*(n-1)-Getdiameter();
    if (k==2)
    {
        int x=p[to];
        while (x)
        {
            e[x].v=e[x^1].v=-1;
            x=p[f[e[x].y]];
        }
        ans2=0;
        for (int i=1;i<=n;i++)
            d[i]=-inf;
        dfs2(1,0);
        ans-=ans2;
    }
    cout<<ans<<endl;
    return 0;
}

技术分享

【BZOJ 1912】 [Apio2010]patrol 巡逻

标签:bzoj   oi   思路题   树的直径   

原文地址:http://blog.csdn.net/regina8023/article/details/45555441

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!