vijos P1144(金典树形DP)

题目连接: vijos P1144 (小胖守皇宫)

描述

huyichen世子事件后,xuzhenyi成了皇上特聘的御前一品侍卫。

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

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

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

格式

输入格式

输入文件中数据表示一棵树,描述如下:

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

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

对于一个n(0 < n <= 1500)个结点的树,结点标号在1到n之间,且标号不重复。

输出格式

输出文件仅包含一个数,为所求的最少的经费。

样例1

样例输入1[复制]

6
1 30 3 2 3 4
2 16 2 5 6
3 5 0
4 4 0
5 11 0
6 5 0

样例输出1[复制]

25

提示

如图

一道金典的树形DP题目:

每个节点有三种状态:

0:受子节点守护。
1:自己守护。
2:受父节点守护
分析:

状态0:dp[u][0]=sum(min(dp[v][0],dp[v][1])),但是必须保证至少有一个儿子1状态,所以要加上dp[v][1]-min(dp[v][0],dp[v][1]) 的最小值。

状态1:dp[u][1]=sum(min(dp[v][0],dp[v][1],dp[v][2]);

状态2:dp[u][2]=sum(min(dp[v][0].dp[v][1]);


P1144小胖守皇宫
Accepted

记录信息

评测状态 Accepted
题目 P1144 小胖守皇宫
递交时间 2013-09-07 23:03:32
代码语言 C++
评测机 上海红茶馆
消耗时间 15 ms
消耗内存 736 KiB
评测时间 2013-09-07 23:03:34

评测结果

编译成功

测试数据 #0: Accepted, time = 0 ms, mem = 676 KiB, score = 14

测试数据 #1: Accepted, time = 0 ms, mem = 676 KiB, score = 14

测试数据 #2: Accepted, time = 0 ms, mem = 680 KiB, score = 14

测试数据 #3: Accepted, time = 15 ms, mem = 736 KiB, score = 14

测试数据 #4: Accepted, time = 0 ms, mem = 676 KiB, score = 14

测试数据 #5: Accepted, time = 0 ms, mem = 676 KiB, score = 14

测试数据 #6: Accepted, time = 0 ms, mem = 680 KiB, score = 14

Accepted, time = 15 ms, mem = 736 KiB, score = 98



#include<stdio.h>
#include<string.h>
const int N=2000;
const int inf=0x3fffffff;
#define min(x,y) (x>y?y:x) 
int dp[N][3];
int n,head[N],num,vis[N],cot[N];
struct edge
{
	int st,ed,next;
}e[N*4];
void addedge(int x,int y)
{
	e[num].st=x;e[num].ed=y;e[num].next=head[x];head[x]=num++;
	e[num].st=y;e[num].ed=x;e[num].next=head[y];head[y]=num++;
}
void dfs(int u)
{
	vis[u]=1;
	int i,v,temp=inf,mm;
	for(i=head[u];i!=-1;i=e[i].next)
	{
		v=e[i].ed;
		if(vis[v]==1)continue;
		dfs(v);
		mm=min(dp[v][0],dp[v][1]);
		dp[u][0]+=mm;
		temp=min(temp,dp[v][1]-mm);//如果有一个最小值是dp[v][1]的话,temp=0,否则求出最小的差值
		dp[u][1]+=min(mm,dp[v][2]);
		dp[u][2]+=mm;
	}
	dp[u][0]+=temp;//如果没有儿子,dp[u][0]=inf;
}
int main()
{
	int i,j,m,x,y,w;
	while(scanf("%d",&n)!=-1)
	{
		memset(head,-1,sizeof(head));
		memset(dp,0,sizeof(dp));
		for(i=1;i<=n;i++)
		{
			scanf("%d%d%d",&x,&w,&m);
			cot[x]=w;
			dp[x][1]=w;
			for(j=0;j<m;j++)
			{
				scanf("%d",&y);
				addedge(x,y);
			}
		}
		memset(vis,0,sizeof(vis));
		dfs(n);
		printf("%d\n",min(dp[n][0],dp[n][1]));
	}
	return 0;
}


你可能感兴趣的:(编程,算法,百度,ACM,树形DP)