zoukankan      html  css  js  c++  java
  • BZOJ 4557 (JLOI 2016) 侦查守卫

    4557: [JLoi2016]侦察守卫

    Time Limit: 20 Sec Memory Limit: 256 MB
    Submit: 493 Solved: 342
    [Submit][Status][Discuss]
    Description

    小R和B神正在玩一款游戏。这款游戏的地图由N个点和N-1条无向边组成,每条无向边连接两个点,且地图是连通的
    。换句话说,游戏的地图是一棵有N个节点的树。游戏中有一种道具叫做侦查守卫,当一名玩家在一个点上放置侦
    查守卫后,它可以监视这个点以及与这个点的距离在D以内的所有点。这里两个点之间的距离定义为它们在树上的
    距离,也就是两个点之间唯一的简单路径上所经过边的条数。在一个点上放置侦查守卫需要付出一定的代价,在不
    同点放置守卫的代价可能不同。现在小R知道了所有B神可能会出现的位置,请你计算监视所有这些位置的最小代价

    Input

    第一行包含两个正整数N和D,分别表示地图上的点数和侦查守卫的视野范围。约定地图上的点用1到N的整数编号。
    第二行N个正整数,第i个正整数表示在编号为i的点放置侦查守卫的代价Wi。保证Wi≤1000。第三行一个正整数M,
    表示B神可能出现的点的数量。保证M≤N。第四行M个正整数,分别表示每个B神可能出现的点的编号,从小到大不
    重复地给出。接下来N–1行,每行包含两个正整数U,V,表示在编号为U的点和编号为V的点之间有一条无向边。N<=
    500000,D<=20
    Output

    仅一行一个整数,表示监视所有B神可能出现的点所需要的最小代价

    Sample Input

    12 2

    8 9 12 6 1 1 5 1 4 8 10 6

    10

    1 2 3 5 6 7 8 9 10 11

    1 3

    2 3

    3 4

    4 5

    4 6

    4 7

    7 8

    8 9

    9 10

    10 11

    11 12
    Sample Output

    10

    —————————————————————————————-

    题解

    树形dp,定义f[x][i]表示以x为根的子树向下i层没有被覆盖的花费,
               g[x][i]表示以x为根的子树完全并覆盖并且向上延伸i层的花费。
    转移方程:
        g[x][i]=min(g[x][i]+f[v][i],g[v][i+1]+f[x][i+1])
        g[x][i]=min(g[x][i],g[x][i+1])
        f[x][0]=g[x][0]
        f[x][i]+=f[v][i-1]
        f[x][i]=min(f[x][i],f[x][i-1])
    

    代码

        #include<iostream>
    #include<cstdio>
    
    using namespace std;
    const int MAXN = 500000+5;
    const int inf = 0x4fffffff;
    
    struct Edge{
        int nxt,to;
    }edge[MAXN*2];
    
    int n,m,D;
    int cos[MAXN],f[MAXN][25],g[MAXN][25];
    int head[MAXN],cnt;
    bool vis[MAXN];
    
    inline void add(int bg,int ed){
        edge[++cnt].to=ed;
        edge[cnt].nxt=head[bg];
        head[bg]=cnt;
    }
    
    inline void dfs(int x,int fa){
        if(vis[x]) f[x][0]=g[x][0]=cos[x];
        for(register int i=1;i<=D;i++) g[x][i]=cos[x];
        g[x][D+1]=inf;
        for(register int i=head[x];i;i=edge[i].nxt){
            int v=edge[i].to;
            if(v==fa) continue;
            dfs(v,x);
            for(register int j=D;j>=0;j--) 
                g[x][j]=min(g[x][j]+f[v][j],g[v][j+1]+f[x][j+1]);
            for(register int j=D;j>=0;j--)
                g[x][j]=min(g[x][j],g[x][j+1]);
            f[x][0]=g[x][0];
            for(register int j=1;j<=D+1;j++)
                f[x][j]+=f[v][j-1];
            for(register int j=1;j<=D+1;j++)
                f[x][j]=min(f[x][j],f[x][j-1]);
        }
    }
    
    int main(){
        scanf("%d%d",&n,&D);
        for(register int i=1;i<=n;i++)
            scanf("%d",&cos[i]);
        scanf("%d",&m);
        for(register int i=1;i<=m;i++){
            int x;
            scanf("%d",&x);
            vis[x]=true;
        }
        for(register int i=1;i<n;i++){
            int x,y;
            scanf("%d%d",&x,&y);
            add(x,y);add(y,x);
        }
        dfs(1,0);
        printf("%d",f[1][0]);
        return 0;
    }
  • 相关阅读:
    SVN使用svn+ssh协议连接服务器时重复提示输入密码 解决办法
    SQL Server 2008 排序函数 ROW_NUMBER和RANK 用法总结
    数据表基础知识(1)
    数据库基本概念
    String函数
    委托
    递归算法
    关于C#引用类型赋值
    BackgroundWorker的应用
    DevExpress_Report 主从报表绑定数据,分页打印
  • 原文地址:https://www.cnblogs.com/sdfzsyq/p/9677086.html
Copyright © 2011-2022 走看看