luoguP3267 [JLOI2016/SHOI2016] 侦查守卫 树dp

传送门

今天开始尽量补一补欠的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\n",f[1][0]);
65     return 0;
66 }
View Code

 

猜你喜欢

转载自www.cnblogs.com/yuyanjiaB/p/9893236.html