• codeforces 337D Book of Evil (树形dp)


    题目链接:http://codeforces.com/problemset/problem/337/D

    参考博客:http://www.cnblogs.com/chanme/p/3265913

    题目大意:给你一个n个点的无向树。任意两点的距离为中间经过的边数。现在某个点上有本魔法书,这本书对与这个点距离小于等于d的点有影响。给你收集到的m个受影响的点(信息不一定全对)。要你判断有多少个点可能放魔法书。

    算法思路:我参考别人的想法,自己开始怎么也想不出好的算法,n也太大。这题用树形dp,两遍dfs来统计出每一个点到所有这个m个受影响点的距离的最大值。只要这个最大值<=d,就可能放魔法书。 所以关键就是算这个最大值,有树形dp第一遍就可以统计以u为根,u到子树中存在的受影响点的最大值。第二遍要利用父亲和兄弟节点来求出u到剩余受影响点(即不在u的子树上的点)的最大值。然后和在一起就是u到所有受影响点的最大值。

    代码:

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #include<vector>
    using namespace std;
    
    const int maxn = 101000;
    const int INF = 0x3f3f3f3f;
    
    int disDown[maxn];   //disDown[u]表示以u为根的子树Pm中的点到u距离的最大值。
    int disUp[maxn];     //disUp[u]表示以u为根去掉上面的子树中的点,u到与父亲相连的所有pm的最大值。
    int Max[maxn];       //Max[u]表示u为根子树Pm中的点到u距离的最大值。
    int SecMax[maxn];    //SecMax[u]表示u为根子树Pm中的点到u距离的第二大值。
    int n,m,d;
    vector<int> G[maxn];
    
    void dfs1(int u,int fa)
    {
        for(int i=0,sz=G[u].size(); i<sz; i++)
        {
            int v = G[u][i];
            if(v == fa) continue;
    
            dfs1(v,u);
            if(disDown[v]+1 > SecMax[u])
            {
                SecMax[u] = disDown[v] + 1;
                if(SecMax[u] > Max[u])
                    swap(SecMax[u],Max[u]);
            }
        }
        disDown[u]=max(disDown[u],Max[u]);
    }
    
    void dfs2(int u,int fa)
    {
        for(int i=0,sz=G[u].size(); i<sz; i++)
        {
            int v = G[u][i];
            if(v == fa) continue;
    
            if(disDown[v] + 1 == Max[u])
                disUp[v] = max( disUp[v] , max(disUp[u],SecMax[u])+1 );
    
            else
                disUp[v] = max( disUp[v] , max(disUp[u],Max[u])+1 );
    
            dfs2(v,u);
        }
    }
    
    int main()
    {
        //freopen("E:\acm\input.txt","r",stdin);
        cin>>n>>m>>d;
    
        memset(disDown,-0x3f,sizeof(disDown));
        memset(disUp,-0x3f,sizeof(disUp));
        memset(Max,-0x3f,sizeof(Max));
        memset(SecMax,-0x3f,sizeof(SecMax));
    
        for(int i=1; i<=m; i++)
        {
            int  pm;
            scanf("%d",&pm);
            disDown[pm] = disUp[pm] = 0;
        }
    
        for(int i=1; i<=n; i++) G[i].clear();
        for(int i=1; i<n; i++)
        {
            int u,v;
            scanf("%d %d",&u,&v);
            G[u].push_back(v);
            G[v].push_back(u);
        }
    
        dfs1(1,-1);
        dfs2(1,-1);
    
        int ans = 0;
        for(int i=1; i<=n; i++)
            if(disDown[i] <= d && disUp[i] <= d)
                ans ++;
        printf("%d
    ",ans);
    }
    View Code
  • 相关阅读:
    Python数据可视化---pygal模块
    Linux常用命令---常用的用户,解压,网络,关机命令
    Python实战---制作专属有声小说(调用百度语音合成接口)
    Linux基本操作---文件搜索命令
    MySQL必知必会1-20章读书笔记
    这是反馈的地方呀
    设计模式--建造者模式
    python 弹窗提示警告框MessageBox
    算法分析设计--递归算法
    Web程序开发最基本的编程模式--MVC编程模式
  • 原文地址:https://www.cnblogs.com/acmdeweilai/p/3330800.html
Copyright © 2020-2023  润新知