题目连接: 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之间,且标号不重复。
输出文件仅包含一个数,为所求的最少的经费。
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
如图
一道金典的树形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]);
评测状态 | 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; }