皇宫看守-树形DP
Description
太平王世子事件后,陆小凤成了皇上特聘的御前一品侍卫。
皇宫以午门为起点,直到后宫嫔妃们的寝宫,呈一棵树的形状;某些宫殿间可以互相望见。大内保卫森严,三步一岗,五步一哨,每个宫殿都要有人全天候看守,在不同的宫殿安排看守所需的费用不同。
可是陆小凤手上的经费不足,无论如何也没法在每个宫殿都安置留守侍卫。
编程任务:帮助陆小凤布置侍卫,在看守全部宫殿的前提下,使得花费的经费最少。
Input
输入文件中数据表示一棵树,描述如下:
第1行 n,表示树中结点的数目。
第2行至第n+1行,每行描述每个宫殿结点信息,依次为:该宫殿结点标号i(0 < i<=n),在该宫殿安置侍卫所需的经费k,该边的儿子数m,接下来m个数,分别是这个节点的m个儿子的标号r1,r2,...,rm。
对于一个n(0 < n <= 1500)个结点的树,结点标号在1到n之间,且标号不重复。
Output
输出文件仅包含一个数,为所求的最少的经费。
Sample Input
6
1 30 3 2 3 4
2 16 2 5 6
3 5 0
4 4 0
5 11 0
6 5 0
Sample Output
25
思路
- f[i][0/1/2]=以i为跟的子树全覆盖所需的最小花费,0表示子树的根被父亲看,1表示子树的根被儿子看,2表示子树的根被自己看
- 看似一样,实则差异巨大的题目:https://www.cnblogs.com/wuwendongxi/p/13767484.html
代码
#include <iostream>
#include <cstdio>
#define maxn 2005
using namespace std;
int head[maxn],cnt,n,r[maxn],c[maxn],f[maxn][3];
struct fdfdfd{int next,to;}e[maxn];
void addedge(int x,int y){e[++cnt].to=y; e[cnt].next=head[x]; head[x]=cnt;}
void dp(int x,int pre)
{
int temp=0x7fffffff;
for(int i=head[x];i;i=e[i].next)
{
int v=e[i].to; dp(v,x);
f[x][0]+=min(f[v][2],f[v][1]);
f[x][2]+=min(f[v][2],min(f[v][1],f[v][0]));
f[x][1]+=min(f[v][2],f[v][1]);
temp=min(temp,f[v][2]-min(f[v][2],f[v][1]));
}
f[x][1]+=temp; f[x][2]+=c[x];
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;++i)
{
int u,v,num; scanf("%d",&u); scanf("%d%d",&c[u],&num);
for(int j=1;j<=num;++j) scanf("%d",&v),addedge(u,v),r[v]=1;
}
int root;
for(int i=1;i<=n;++i)
if(!r[i]) {root=i; break;}
dp(root,0);
printf("%d",min(f[root][1],f[root][2]));
return 0;
}