(树形DP) bzoj 1912

1912: [Apio2010]patrol 巡逻

Time Limit: 4 Sec  Memory Limit: 64 MB
Submit: 684  Solved: 387
[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

 
转载的。。很清晰啊

题目大意

给一棵树,求加k条边之后,从1号点遍历每个点之后再回到1号点的最小距离和。k=12

思路

如果不加边,那么遍历走过的距离显然是2(n1)。注意到一个很有意思的限制:k=12。那么可以分类讨论以下两种情况 
1、k=1,很显然最优的方法就是在树的最长路径xy之间连一条边,这样xy之间的距离缩短为1,这个最长路径就是树的直径,我们可以DFS求一遍树的直径len1,那么最终答案为2(n1)len1+1 
另外为了情况2的方便,要在DFS过程中用链表记录下树的直径的路径。这个路径是两条路径相交而成的,假设这两条路径的交点为x:一条是x下面的最长路,另一条是x下面的次长路(注意它也是包含了y下面的最长路),如下图 
这里写图片描述 
除非次长路为0(x下面是一条链),否则直径一定是这样的形态

2、k=2,肯定是找树中次长路径xy,给xy之间连边,我们在情况1的基础上,将第一次DFS求得的树的直径上的所有边边权全部标为-1,再DFS一次,求出树中的次长路径len2,最终答案为2(n1)len1+1len2+1

 

不知道自己的代码为嘛会WA了。。求指教啊。。。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<cstdlib>
#include<algorithm>
using namespace std;
int n,k,cnt=1,maxx,st;
struct node
{
    int x,to,len,next;
}e[200005];
int son1[200005],son2[200005],head[100005];
void add(int x,int y,int len)
{
    cnt++;
    e[cnt].to=y;
    e[cnt].len=len;
    e[cnt].next=head[x];
    head[x]=cnt;
}
int dfs(int u,int father)
{
    int max1=0,max2=0;
    for(int i=head[u];i;i=e[i].next)
    {
        int v=e[i].to;
        int w=e[i].len;
        if(v==father) continue;
        int now=dfs(v,u)+w;
        if(now>max1)
        {
            max2=max1,son2[u]=son1[u];
            max1=now,son1[u]=i;
        }
        else if(now>max2)
        {
            max2=now;
            son2[u]=i;
        }
    }
    if(maxx<(max1+max2))
        maxx=max1+max2,st=u;
    return max1;
}
int main()
{
    scanf("%d%d",&n,&k);
    for(int i=1;i<n;i++)
    {
        int x,y,z;
        scanf("%d%d",&x,&y);
        add(x,y,1);
        add(y,x,1);
    }
    int ans=0;
    ans=2*(n-1);
    dfs(1,-1);
    ans=ans-maxx+1;
    if(k==2)
    {
        for(int i=son1[st];i;i=son1[e[i].to])
            e[i].len=e[i^1].len=-1;
        for(int i=son2[st];i;i=son2[e[i].to])
            e[i].len=e[i^1].len=-1;
        dfs(1,-1);
        ans=ans-maxx+1;
    }
    printf("%d\n",ans);
    return 0;
}

  

posted @ 2015-05-19 15:22  waterfull  阅读(166)  评论(0编辑  收藏  举报