loj10157 皇宫看守

题目描述

太平王世子事件后,陆小凤成了皇上特聘的御前一品侍卫。

皇宫以午门为起点,直到后宫嫔妃们的寝宫,呈一棵树的形状,某些宫殿间可以互相望见。大内保卫森严,三步一岗,五步一哨,每个宫殿都要有人全天候看守,在不同的宫殿安排看守所需的费用不同。

可是陆小凤手上的经费不足,无论如何也没法在每个宫殿都安置留守侍卫。

帮助陆小凤布置侍卫,在看守全部宫殿的前提下,使得花费的经费最少。

loj10157 皇宫看守_第1张图片

输入格式

输入中数据描述一棵树,描述如下:

第一行 n,表示树中结点的数目。

第二行至第 n+1 行,每行描述每个宫殿结点信息,依次为:该宫殿结点标号 i (0 < i ≤ n),在该宫殿安置侍卫所需的经费 k,该边的儿子数 m,接下来 m个数,分别是这个节点的 m 个儿子的标号r1,r2,⋯,rm​​。

对于一个 n个结点的树,结点标号在 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

样例解释

有六个区域被安排的情况如左图所示。

如右图,灰色点安排了警卫,2 号警卫可以观察 1,2,5,6,3 号警卫可以观察 1,3,4号警卫可以观察 1,4。

总费用:16+5+4=25

loj10157 皇宫看守_第2张图片loj10157 皇宫看守_第3张图片

数据范围与提示

对于 100%的数据,0

用 f [x ][0] 表示这个节点可以在父亲节点里被看到,f [ x ][ 1]表示这个节点可以在它的子节点被看到,f [ x][ 2]表示在这个节点上自身就放了一个守卫。

#include
#include
#include
#include
using namespace std;
const int N = 2005;
int n,cnt = 0;
int c[N],h[N],f[N][3],v[N];
struct node{
	int z,nex;
}e[2*N];
int add(int x,int y)
{
	cnt++;
	e[cnt].z = y;
	e[cnt].nex = h[x];
	h[x] = cnt;	
}
void dp(int x,int fa)
{
	int d = 0xfffffff;
	for(int i = h[x];i != 0;i = e[i].nex)
	{
		int y = e[i].z;
		if(y == fa)continue;
		dp(y,x);
		f[x][0] += min(f[y][2],f[y][1]);
		f[x][1] += min(f[y][2],f[y][1]);
		d = min(d,f[y][2] - min(f[y][2],f[y][1])); //此情况下子节点上一定要放一个士兵
		f[x][2] += min(f[y][2],min(f[y][1],f[y][0]));
	}
	f[x][1] += d;
	f[x][2] += c[x];
}
int main()
{
	scanf("%d",&n);
	for(int i = 1;i <= n;i++)
	{
		int x,num;
		scanf("%d",&x);
		scanf("%d%d",&c[x],&num);
		for(int j = 1;j <= num;j++)
		{
			int y;
			scanf("%d",&y);
			add(x,y);
			v[y] = 1;
		}
	}
	int root = 1;
	while(v[root] != 0)root++;
	dp(root,0);
	printf("%d",min(f[root][1],f[root][2]));
	return 0;
}

 

你可能感兴趣的:(动态规划)