zoukankan      html  css  js  c++  java
  • luogu P3267 [JLOI2016/SHOI2016] 侦查守卫

    传送门

    今天开始尽量补一补欠的70多道题的blog...(菜啊)

    都是几句话的事 周末大概就完了

     

    一看不是树dp经典题吗 最小覆盖

    然后告诉我有些点不必覆盖?

    20minutes later 发现其实是一样的...因为不必覆盖不是一定不能覆盖

    其实是我一开始想成记录放的节点个数那个题 然后状态设计跪了

    还是说一下数组吧:

    f[i][j]表示从i点向下 已知 的子树最多延伸j步没有覆盖的最小花费

    g[i][j]表示从i点向上 已知 的子树最多能延伸j步覆盖其他点的最小花费

    自然遍历儿子的时候先递归 回溯的时候更新

    先是g[x][i]

    逆序更新

    我们要加上现在这个子树所有的点 两种情况:

    g[x][i] = g[x][i] + f[sn][i] 利用其他子树覆盖 最多覆盖j的距离所以j以下由后面那个f[][]覆盖

    g[x][i] = g[sn][i+1] + f[x][i+1] 利用这个子树覆盖 可以覆盖其他子树i-1的距离 i及一下由后面那个f[][]覆盖

    然后取最小值

    (自己画个图就OK)

    然后更新f[x][i]

    顺序更新

    首先f[x][0] = g[x][0](意义相同)

    然后f[x][i] = ∑(v∈sn)f[sn][i-1] 同上 i-1步以下要覆盖好

    同时g[x][i]  = min(g[x][i],g[x][i+1]) f[x][i] = min(f[x][i],f[x][i-1]) (可以看做是后面两项的退化)

    然后就是初始化 如果要求覆盖该点那么f[x][0] = g[x][0] = w[x] 

    同时更新之前先判断x放点 也就是g[x][i] = w[x]

    (没想到小细节一说出来挺多的...)

    注意g[x][d+1] = inf....

    不要设f[]g[]初值是inf....inf不要太大.....

    Time cost: 55min

    Code:

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 #include<queue>
     5 #include<iostream>
     6 #include<cmath>
     7 #define ms(a,b) memset(a,b,sizeof a)
     8 #define rep(i,a,n) for(int i = a;i <= n;i++)
     9 #define per(i,n,a) for(int i = n;i >= a;i--)
    10 #define inf 1e9+7
    11 using namespace std;
    12 typedef long long ll;
    13 typedef double D;
    14 #define eps 1e-8
    15 ll read() {
    16     ll as = 0,fu = 1;
    17     char c = getchar();
    18     while(c < '0' || c > '9') {
    19         if(c == '-') fu = -1;
    20         c = getchar();
    21     }
    22     while(c >= '0' && c <= '9') {
    23         as = as * 10 + c - '0';
    24         c = getchar();
    25     }
    26     return as * fu;
    27 }
    28 //head
    29 const int N = 500005;
    30 int n,d;
    31 int head[N],nxt[N<<1],mo[N<<1],cnt;
    32 void _add(int x,int y) {
    33     mo[++cnt] = y;
    34     nxt[cnt] = head[x];
    35     head[x] = cnt;
    36 }
    37 void add(int x,int y) {if(x^y)_add(x,y),_add(y,x);}
    38 bool vis[N];
    39 int w[N],f[N][21],g[N][21];
    40 
    41 void dfs(int x,int p) {
    42     if(vis[x]) f[x][0] = g[x][0] = w[x];
    43     rep(i,1,d) g[x][i] = w[x];
    44     g[x][d+1] = (int)inf;
    45     for(int i = head[x];i;i = nxt[i]) {
    46         int sn = mo[i];
    47         if(sn == p) continue;
    48         dfs(sn,x);
    49         per(i,d,0) g[x][i] = min(g[x][i] + f[sn][i],f[x][i+1] + g[sn][i+1]);
    50         per(i,d,0) g[x][i] = min(g[x][i],g[x][i+1]);
    51         f[x][0] = g[x][0];
    52         rep(i,1,d+1) f[x][i] += f[sn][i-1];
    53         rep(i,1,d+1) f[x][i] = min(f[x][i],f[x][i-1]);
    54     }
    55 }
    56 
    57 int main() {
    58     n = read(),d = read();
    59     rep(i,1,n) w[i] = read();
    60     int m = read();
    61     rep(i,1,m) vis[read()] = 1;
    62     rep(i,2,n) add(read(),read());
    63     dfs(1,1);
    64     printf("%d
    ",f[1][0]);
    65     return 0;
    66 }
    View Code

     

    > 别忘了 总有人在等着你
  • 相关阅读:
    Callable的Future模式
    并发队列
    并发工具类
    线程池
    并发编程专题
    侧边栏:内有友链,分类等等
    脑残错误记录
    博主的OI流水账
    NOI2019游记
    NOI数论姿势瞎总结(Pi也没有)
  • 原文地址:https://www.cnblogs.com/yuyanjiaB/p/9893236.html
Copyright © 2011-2022 走看看