• (树形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
    ",ans);
        return 0;
    }
    

      

  • 相关阅读:
    javascript字符串加密解密函数
    javascript实现blob加密视频源地址
    HTML网页实现flv视频播放
    DELL r720远控装系统
    nginx笔记
    Centos7防火墙配置
    CentOS7.x搭建LNMP
    搭建可道云私人云盘系统
    网络设备巡检常用命令-摘自星球成员马磊分享
    部署Windows Server 2012的WSUS补丁服务器
  • 原文地址:https://www.cnblogs.com/water-full/p/4514654.html
Copyright © 2020-2023  润新知