【树形dp】vijos1144小胖守皇宫
细节很精妙
描述
huyichen世子事件后,xuzhenyi成了皇上特聘的御前一品侍卫。
皇宫以午门为起点,直到后宫嫔妃们的寝宫,呈一棵树的形状;某些宫殿间可以互相望见。大内保卫森严,三步一岗,五步一哨,每个宫殿都要有人全天候看守,在不同的宫殿安排看守所需的费用不同。
可是xuzhenyi手上的经费不足,无论如何也没法在每个宫殿都安置留守侍卫。
帮助xuzhenyi布置侍卫,在看守全部宫殿的前提下,使得花费的经费最少。
格式
输入格式
输入文件中数据表示一棵树,描述如下:
第1行 n,表示树中结点的数目。
第2行至第n+1n+1行,每行描述每个宫殿结点信息,依次为:该宫殿结点标号i(0<i \le n0<i≤n),在该宫殿安置侍卫所需的经费k,该点的儿子数m,接下来m个数,分别是这个节点的m个儿子的标号r_1, r_2, \cdots, r_mr1,r2,⋯,rm。
对于一个n(0 < n \le 15000<n≤1500)个结点的树,结点标号在1到n之间,且标号不重复。保证经费总和不超过2^31-1231−1。
输出格式
输出文件仅包含一个数,为所求的最少的经费。
题目分析
有些细节处理真的是非常精妙。
分析详见初涉树形dp【权最小点覆盖】vijos1144皇宫看守
1 #include<bits/stdc++.h> 2 const int maxn = 2003; 3 4 int f[maxn][3],a[maxn],n,rt; 5 int head[maxn],nxt[maxn<<1],edges[maxn<<1],edgeTot; 6 bool vis[maxn]; 7 8 int read() 9 { 10 char ch = getchar(); 11 int num = 0; 12 bool fl = 0; 13 for (; !isdigit(ch); ch = getchar()) 14 if (ch=='-') fl = 1; 15 for (; isdigit(ch); ch = getchar()) 16 num = (num<<1)+(num<<3)+ch-48; 17 if (fl) num = -num; 18 return num; 19 } 20 inline int min(int a, int b){return a<b?a:b;} 21 inline int min(int a, int b, int c){int t=min(a,b);return t<c?t:c;} 22 void addedge(int u, int v) 23 { 24 edges[++edgeTot] = v, nxt[edgeTot] = head[u], head[u] = edgeTot; 25 vis[v] = 1; 26 } 27 void dfs(int now) 28 { 29 int delta = 2e9; 30 for (int i=head[now]; i!=-1; i=nxt[i]) 31 { 32 int v = edges[i]; 33 dfs(v); 34 f[now][0] += min(f[v][1], f[v][2]); 35 f[now][1] += min(f[v][1], f[v][2]); 36 delta = min(f[v][2]-f[v][1], delta); 37 f[now][2] += min(f[v][0], f[v][1], f[v][2]); 38 } 39 delta = std::max(delta, 0); 40 f[now][1] += delta; 41 } 42 int main() 43 { 44 memset(head, -1, sizeof head); 45 n = read(); 46 for (int i=1; i<=n; i++) 47 { 48 int p = read(), k; 49 f[p][2] = a[p] = read(), k = read(); 50 while (k--) addedge(p, read()); 51 } 52 rt = 1; 53 while (vis[rt]) rt++; 54 dfs(rt); 55 printf("%d\n",min(f[rt][1], f[rt][2])); 56 return 0; 57 }
END