警卫安排(security.pas/c/cpp)
一个重要的基地被分为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。
这道题是明显的DP,他的分布是树型的。数据规模小,只要DFS+DP即可
每个安全结点i都有3个合法状态,分别为:
1.被父亲结点上安排的警卫看到,设为f[i][0]。
2.在该结点安排警卫,设为f[i][1]。
3.被子结点上安排的警卫看到,设为f[i][2]。
现在只需针对三种状态,设计出状态转移方程。
对于f[i][0],i的每个子节点要么安排警卫,要么被其子结点安排的警卫看到,所以有:
f[i][0]=∑min(f[k][1],f[k][2]), k为i的子结点
对于f[i][1],i的每个子结点可以任取一种状态,所以有:
f[i][1]= ∑min(f[k][0],f[k][1],f[k][2])+w[i], k为i的子结点
对于f[i][2],则需要枚举一个子结点安排警卫,其他子结点可任取状态2和状态3,所以有:
f[i][2]= ∑min(f[k][1],f[k][2])+f[j][1],k为i的子结点
j为枚举的点,k≠j。
状态转移方程并不难想,关键是它的分类情况
pascal:
c: