【问题描述】
太平王世子事件后,陆小凤成了皇上特聘的御前一品侍卫。 皇宫以午门为起点,直到后宫嫔妃们的寝宫,呈一棵树的形状;有边直接相连的宫殿可以互相望见。大内保卫森严,三步一岗,五步一哨,每个宫殿都要有人全天候看守,在不同的宫殿安排看守所需的费用不同。 可是陆小凤手上的经费不足,无论如何也没法在每个宫殿都安置留守侍卫。
编程任务:帮助陆小凤布置侍卫,在看守全部宫殿的前提下,使得花费的经费最少。
【输入格式】
输入文件中数据表示一棵树,描述如下:
第1行 n,表示树中结点的数目。
第2行至第n+1行,每行描述每个宫殿结点信息,依次为:该宫殿结点标号i(0<I<=N),在该宫殿安置侍卫所需的经费K,该点的儿子数M,接下来M个数,分别是这个节点的M个儿子的标号R1,R2,...,RM。对于一个n(0 < n<=1500)个结点的树,结点标号在1到n之间,且标号不重复。
【输出格式】
输出文件仅包含一个数,为所求的最少的经费。
【输入样例】
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
【解析】
这道题也是一道树形状态的动态规划啦.. #我在用肺说话..
这道题需要我们去定每一个点的状态.. 也就是关于该点是否有人和是否安全..
f[i][0]表示i点 没人 安全 所需的最小花费
f[i][1]表示i点 没人 不安全 所需的最小花费
f[i][2]表示i点 有人 安全 所需的最小花费
f[i][3]表示i点 有人 不安全 所需的的最小花费.. #第四种就不说啦.. 既然有人怎么会不安全呢.. 那么就可以不定义这种状态..
这个时候也许你就会问了.. f[i][1]有什么用.. 没人不安全的最小花费不就是0吗
这你就错了.. 我定义这些最小花费的前提是当前节点i为根的数中所有孩子节点都是安全情况下的..
那么问题来了 = =
没人并且安全这种状态怎么得到0.0.
如果想让一个节点没人安全,孩子节点中必须要有一个是有人的,但有人的孩子节点又可以有很多..
问题就出在这里.. 这个问题想了我挺久..
<pre name="code" class="cpp">void Tree_DP ( int x ){ int i, j, k, y, f0, f1, f2; f0 = f1 = 0; f2 = w[x]; int minn = 99999; bool bk = false; for ( k = first[x]; k; k = a[k].next ){ y = a[k].y; Tree_DP (y); minn = _min ( minn, f[y][2] - f[y][0] ); if ( f[y][2] > f[y][0] ) f0 += f[y][0]; else { bk = true; f0 += f[y][2]; } f1 += f[y][0]; f2 += _min ( f[y][0], _min ( f[y][1], f[y][2] ) ); } if ( bk == false ) f0 += minn; f[x][0] = f0; f[x][1] = f1; f[x][2] = f2; }注意看以上代码关于f0、minn的部分..
我在孩子节点中间找一个从没人安全到有人安全的最小增加的花费(在这里我默认所有孩子节点有人安全都比没人安全花费多)
那么假如有一个孩子节点的有人安全比没人安全的花费少,那么不就解决了需要有人的这个问题了吗..就加上孩子节点有人安全的花费并标记bk已经找到了有人花费少的节点
最后如果还是没有,那就加上minn..
详细的就自己看吧..
【完整代码】
#include <cstdio> #include <cstring> #include <cstdlib> using namespace std; struct node { int x, y, next; }a[2100]; int first[2100], len, n; void ins ( int x, int y ){ len ++; a[len].x = x; a[len].y = y; a[len].next = first[x]; first[x] = len; } int f[2100][3], w[2100]; int _min ( int x, int y ){ return x < y ? x : y; } void Tree_DP ( int x ){ int i, j, k, y, f0, f1, f2; f0 = f1 = 0; f2 = w[x]; int minn = 99999; bool bk = false; for ( k = first[x]; k; k = a[k].next ){ y = a[k].y; Tree_DP (y); minn = _min ( minn, f[y][2] - f[y][0] ); if ( f[y][2] > f[y][0] ) f0 += f[y][0]; else { bk = true; f0 += f[y][2]; } f1 += f[y][0]; f2 += _min ( f[y][0], _min ( f[y][1], f[y][2] ) ); } if ( bk == false ) f0 += minn; f[x][0] = f0; f[x][1] = f1; f[x][2] = f2; } bool v[2100]; int main (){ int i, j, k, x, y; scanf ( "%d", &n ); len = 0; memset ( first, 0, sizeof (first) ); memset ( v, false, sizeof (v) ); for ( i = 1; i <= n; i ++ ){ scanf ( "%d", &x ); scanf ( "%d%d", &w[x], &k ); for ( j = 1; j <= k; j ++ ){ scanf ( "%d", &y ); ins ( x, y ); v[y] = true; } } int st; for ( i = 1; i <= n; i ++ ){ if ( v[i] == false ){ st = i; break; } } Tree_DP (st); printf ( "%d\n", _min ( f[st][0], f[st][2] ) ); return 0; }