• 树形dp-CF-337D. Book of Evil


    题目链接:

    http://codeforces.com/problemset/problem/337/D

    题目大意:

    给一棵树,m个点,一个距离d,求有多少个点A,使得A到所有的m个点距离都不超过d.

    解题思路:

    树形dp.

    有两种方法可以解:

    1、类似于树的直径的求法,先以任意一点作为树根,找到距离该点最远的m中的A点(A点一定是m个点中距离相距最远的两点的一个端点),然后以A点作为树根,依次计算各点到A点的最短距离d1[],并找到距离最远的m中的点B点,然后以B点为树根,依次找到各点到B点的距离d2[].  最后再扫一遍,找到d1和d2都不超过d的点。这种方法求比较简单。

    2、先以m中任意一点为树根,在子树中,求出每个节点到达m中的点的最大距离max1,达到max1的直接儿子pre,次大距离。然后再从该根出发,递归维护一个值从父亲过来并且不是通过该节点的最大距离。每次求儿子时判断下,是不是等于该节点的pre,如果是的话,从次大中找。

    树很灵活,递归很强大。多做些树上的题。

    代码:

    #include<iostream>
    #include<cmath>
    #include<cstdio>
    #include<cstdlib>
    #include<string>
    #include<cstring>
    #include<algorithm>
    #include<vector>
    #include<map>
    #include<set>
    #include<stack>
    #include<list>
    #include<queue>
    #define eps 1e-6
    #define INF 0x1f1f1f1f
    #define PI acos(-1.0)
    #define ll __int64
    #define lson l,m,(rt<<1)
    #define rson m+1,r,(rt<<1)|1
    #pragma comment(linker, "/STACK:1024000000,1024000000")
    using namespace std;
    
    
    //freopen("data.in","r",stdin);
    //freopen("data.out","w",stdout);
    #define Maxn 110000
    //
    struct Node
    {
       int max1,max2,pre; //只用保存在子树中,该点到给定点的最大距离、次大距离以及最大距离的直接儿子编号
                          //向下推进的时候,维护一个从父亲到达该点的最大值
    }node[Maxn];
    
    struct Edge
    {
       int v;
       struct Edge *next;
    }*head[Maxn<<1],edge[Maxn<<1]; //无向边
    bool pm[Maxn];
    int n,m,d,ans,cnt;
    
    void add(int a,int b)
    {
       ++cnt;
       edge[cnt].v=b;
       edge[cnt].next=head[a],head[a]=&edge[cnt];
    }
    void dfs1(int pre,int cur)
    {
       if(pm[cur]) //如果是给定的点 距离为0,否则置为无穷大
          node[cur].max1=node[cur].max2=0;
       else
          node[cur].max1=node[cur].max2=-INF;
       struct Edge * p=head[cur];
       while(p)
       {
          if(p->v!=pre)
          {
             dfs1(cur,p->v);//先求出儿子
             if(node[p->v].max1+1>=node[cur].max1) //用儿子来更新最大值
             {
                node[cur].max2=node[cur].max1;//更新次大值
                node[cur].max1=node[p->v].max1+1;
                node[cur].pre=p->v;
             }
             else
             {  //更新次大值
                if(node[p->v].max1+1>node[cur].max2)
                   node[cur].max2=node[p->v].max1+1;
             }
          }
          p=p->next;
       }
    }
    void dfs2(int pre,int cur,int pa) //往下递归的时候,顺便判断,决定出来
    {
       if(max(node[cur].max1,pa)<=d) //从父亲和孩子的最大距离不超过d的话,肯定是可以的
          ans++;
       struct Edge * p=head[cur];
       while(p)
       {
          if(p->v!=pre)
          {
             if(p->v==node[cur].pre) //如果最大值是从该儿子更新过来的,从次大值中选
                dfs2(cur,p->v,max(node[cur].max2,pa)+1);
             else
                dfs2(cur,p->v,max(node[cur].max1,pa)+1);
          }
          p=p->next;
       }
    }
    
    int main()
    {
       int a,b,aa;
    
       while(~scanf("%d%d%d",&n,&m,&d))
       {
          memset(pm,false,sizeof(pm));
          memset(head,NULL,sizeof(head));
          for(int i=1;i<=m;i++)
          {
             scanf("%d",&a);
             pm[a]=true; //标记能够攻击的点
          }
          for(int i=1;i<n;i++)
          {
             scanf("%d%d",&aa,&b);
             add(aa,b);
             add(b,aa);
          }
          ans=0;
          if(pm[1]) //如果是给定的m中点,从父亲过来的为0
          {
             dfs1(-1,1);
             dfs2(-1,1,0);
          }
          else //如果不是给定的m中的点,从父亲过来的为-INF
          {
             dfs1(-1,1);
             dfs2(-1,1,-INF);
          }
    
         // dfs1(-1,a);
         /* for(int i=1;i<=n;i++)
             printf("i:%d %d pre:%d
    ",i,node[i].max1,node[i].pre);*/
         // dfs2(-1,a,0); //最后一个参数表示从父亲过来的最大距离,
          //注意不能从任意一点开始,因为从该点的父亲过来的不为0,为-INF.
          printf("%d
    ",ans);
       }
       return 0;
    }
    /*
    10 1 0
    3
    10 1
    1 3
    8 3
    3 5
    5 7
    5 4
    2 4
    9 4
    6 4
    */
    




  • 相关阅读:
    奋斗了一晚上,搞定了Ant
    我很成功,我很失败
    管理复杂性
    Rapid framework(SSH)数据流概述
    Strtus2 Convention Plugin学习(转)
    16X16 经典silk图标 (famfamfam.com)
    v512 Oracle数据库实用教程 演示用ppt(转pdf)
    RapidFramework使用Oracle的步骤
    oracle 找出最耗资源的sql (dolphin_ygj)
    jquery validate 中文化
  • 原文地址:https://www.cnblogs.com/james1207/p/3278001.html
Copyright © 2020-2023  润新知