P1472警卫安排
|
问题描述
一个重要的基地被分为n个连通的区域。出于某种神秘的原因,这些区域以一个区域为核心,呈一颗树形分布。
在每个区域安排警卫所需要的费用是不同的,而每个区域的警卫都可以望见其相邻的区域,只要一个区域被一个警卫望见或者是安排有警卫,这个区域就是安全的。你的任务是:在确保所有区域都是安全的情况下,找到安排警卫的最小费用。
输入格式
第一行n,表示树中结点的数目。
接下来的n行描述了n个区域的信息,每一行包含的整数依次为:区域的标号i(0<i<=n),在区域i安排警卫的费用k,区域i的子结点数目m,接下来m个数为区域i的子结点编号。
输出格式
一行一个整数,为最小的安排费用。
样例输入
6
1 30 3 2 3 4
2 16 2 5 6
3 5 0
4 4 0
5 11 0
6 5 0
样例输出
25
提示
对于所有的数据,0<n<=720。
【题解】
“
“
——by 朱全民
1 #include <iostream> 2 #include <cstdio> 3 #include <cstdlib> 4 #include <cstring> 5 #include <cmath> 6 #include <algorithm> 7 #define min(a, b) ((a) < (b) ? (a) : (b)) 8 #define max(a, b) ((a) > (b) ? (a) : (b)) 9 10 inline void read(int &x) 11 { 12 x = 0;char ch = getchar(), c = ch; 13 while(ch < '0' || ch > '9')c = ch, ch = getchar(); 14 while(ch <= '9' && ch >= '0')x = x * 10 + ch - '0', ch = getchar(); 15 if(c == '-')x = -x; 16 } 17 18 const int INF = 0x3f3f3f3f; 19 const int MAXN = 800 + 10; 20 21 int n,cost[MAXN]; 22 23 struct Edge 24 { 25 int u,v,next; 26 Edge(int _u, int _v, int _next){u = _u;v = _v;next = _next;} 27 Edge(){} 28 }edge[MAXN << 1]; 29 30 int head[MAXN],cnt; 31 32 inline void insert(int a, int b) 33 { 34 edge[++cnt] = Edge(a,b,head[a]); 35 head[a] = cnt; 36 } 37 38 int fa[MAXN], dp[MAXN][3]; 39 /* 40 dp[i][0]表示i放警卫的最小费用 41 dp[i][1]表示i被儿子看到的最小费用 42 dp[i][2]表示i被父亲看到的最小费用 43 44 dp[i][0] = Σmin(dp[son[i]][2], dp[son[i]][0],dp[son[i][1]) + cost[i] 45 dp[i][1] = Σmin(dp[son[i]][0], dp[son[i]][1]) + dp[j][0] j从son[i]中除去 46 dp[i][2] = Σmin(dp[son[i]][1], dp[son[i]][2]) 47 */ 48 49 void dfs(int u) 50 { 51 if(!u)return; 52 register int num = 0, v, cnt, tmp;//先更新0 2 53 for(register int pos = head[u];pos;pos = edge[pos].next) 54 { 55 v = edge[pos].v; 56 if(v == fa[u])continue; 57 fa[v] = u; 58 ++ num; 59 dfs(v); 60 dp[u][0] += min(dp[v][2], min(dp[v][0], dp[v][1])); 61 dp[u][2] += min(dp[v][1], dp[v][0]); 62 } 63 if(!num) 64 { 65 dp[u][0] = cost[u]; 66 dp[u][1] = INF; 67 dp[u][2] = 0; 68 return; 69 } 70 dp[u][0] += cost[u]; 71 dp[u][1] = INF; 72 for(register int i = 1;i <= num;++ i) 73 { 74 cnt = 1; 75 tmp = 0; 76 for(register int pos = head[u];pos;pos = edge[pos].next, ++ cnt) 77 { 78 v = edge[pos].v; 79 if(v == fa[u]) 80 { 81 -- cnt; 82 continue; 83 } 84 if(cnt == i)tmp += dp[v][0]; 85 else tmp += min(dp[v][0], dp[v][1]); 86 } 87 dp[u][1] = min(dp[u][1], tmp); 88 } 89 } 90 91 int main() 92 { 93 read(n); 94 register int root, tmp1,tmp2; 95 for(register int i = 1;i <= n;++ i) 96 { 97 read(root),read(cost[root]),read(tmp1); 98 for(register int j = 1;j <= tmp1;++ j) 99 { 100 read(tmp2); 101 insert(root, tmp2),insert(tmp2, root); 102 } 103 } 104 dfs(root); 105 printf("%d", min(dp[root][0], dp[root][1])); 106 return 0; 107 }