Vijos1144小胖守皇宫【树形DP】

皇宫看守

太平王世子事件后,陆小凤成了皇上特聘的御前一品侍卫。
皇宫以午门为起点,直到后宫嫔妃们的寝宫,呈一棵树的形状;某些宫殿间可以互相望见。大内保卫森严,三步一岗,五步一哨,每个宫殿都要有人全天候看守,在不同的宫殿安排看守所需的费用不同。
可是陆小凤手上的经费不足,无论如何也没法在每个宫殿都安置留守侍卫。
编程任务:帮助陆小凤布置侍卫,在看守全部宫殿的前提下,使得花费的经费最少。

输入格式:

输入数据由文件名为Guard.in的文本文件提供。输入文件中数据表示一棵树,描述如下:
第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[2][2]表示状态下的,f[1][1]表示该节点有人,能守卫;f[0][1]表示该节点无人,但能被子节点守卫;f[0][0]表示该节点无人,不能被子节点守卫;f[1][0]无意义。然后动规:f[0][0]=∑子节点f[0][1];f[1][1]=∑子节点三个状态中最小的一个;f[0][1]=保证子节点中至少有一个有人的状态下子节点的f[1][1]与f[0][1]的累加(f[0][0]不能算进去,因为该节点及其子节点均无人)
 1 #include<cstdio>
 2 #include<iostream>
 3 using namespace std;
 4 struct node{
 5     int size,son[21],f[2][2],w;///f[GuardPresence][Guarded]
 6 }T[1501];
 7 int n;
 8 bool havef[1501];
 9 inline void dfs(int x)
10 {
11     for(int i=1;i<=T[x].size;i++)
12     {
13         dfs(T[x].son[i]);
14         T[x].f[0][0]+=T[T[x].son[i]].f[0][1];
15         T[x].f[1][1]+=min(T[T[x].son[i]].f[0][0],min(T[T[x].son[i]].f[1][1],T[T[x].son[i]].f[0][1]));
16     }
17     T[x].f[1][1]+=T[x].w;
18     int tmp=200000000,p=0;
19     bool flag=false;
20     for(int i=1;i<=T[x].size;i++) if(T[T[x].son[i]].f[1][1]<=T[T[x].son[i]].f[0][1]){flag=true;break;}
21     if(!flag)
22     {
23         for(int i=1;i<=T[x].size;i++) if(tmp>T[T[x].son[i]].f[1][1]-T[T[x].son[i]].f[0][1])
24         {
25             tmp=T[T[x].son[i]].f[1][1]-T[T[x].son[i]].f[0][1];
26             p=i;
27         }
28         T[x].f[0][1]+=T[T[x].son[p]].f[1][1];
29         for(int i=1;i<=T[x].size;i++) if(i!=p) T[x].f[0][1]+=T[T[x].son[i]].f[0][1];
30     }
31    else for(int i=1;i<=T[x].size;i++)T[x].f[0][1]+=min(T[T[x].son[i]].f[0][1],T[T[x].son[i]].f[1][1]);
32     return;
33 }
34 int main()
35 {
36     int num;
37     T[0].f[1][1]=T[0].f[1][0]=100000000;
38     scanf("%d",&n);
39     for(int i=1;i<=n;i++)
40     {
41         scanf("%d",&num);
42         scanf("%d%d",&T[num].w,&T[num].size);
43         for(int j=1;j<=T[num].size;j++)
44         {
45             scanf("%d",&T[num].son[j]);
46             havef[T[num].son[j]]=1;
47         }
48     }
49     int root;
50     for(int i=1;i<=n;i++) if(havef[i]==0){root=i;break;}
51     dfs(root);
52     printf("%d",min(T[root].f[1][1],T[root].f[0][1]));
53     return 0;
54 }
时间: 2024-10-14 01:07:17

Vijos1144小胖守皇宫【树形DP】的相关文章

小胖守皇宫(VIJOS P1144 )题解

题目描述 huyichen世子事件后,xuzhenyi成了皇上特聘的御前一品侍卫. 皇宫以午门为起点,直到后宫嫔妃们的寝宫,呈一棵树的形状:某些宫殿间可以互相望见.大内保卫森严,三步一岗,五步一哨,每个宫殿都要有人全天候看守,在不同的宫殿安排看守所需的费用不同. 可是xuzhenyi手上的经费不足,无论如何也没法在每个宫殿都安置留守侍卫. 帮助xuzhenyi布置侍卫,在看守全部宫殿的前提下,使得花费的经费最少. 输入格式 输入文件中数据表示一棵树,描述如下: 第1行 nn,表示树中结点的数目.

树形dp小胖守皇宫(vijosP1144)

题目链接:https://vijos.org/p/1144 题解:这道题的动归稍稍有一点的复杂,因为一个节点有可能被它的子节点观察,也有可能被父节点观察: 所以我们这样表示: f[i][0](表示当前i节点放了一个看守,即他自己和所有子节点已经被控制好) f[i][1](表示当前i节点不放看守,但是他自己和所有子节点已经被控制好) f[i][2](表示当前解点不放看守,子节点已被控制好但他自己没被控制) f[i][0]=sum(min(f[son][0],f[son][1],f[son][2])

vijos1144(小胖守皇宫)

也是ural1039 描述 huyichen世子事件后,xuzhenyi成了皇上特聘的御前一品侍卫. 皇宫以午门为起点,直到后宫嫔妃们的寝宫,呈一棵树的形状:某些宫殿间可以互相望见.大内保卫森严,三步一岗,五步一哨,每个宫殿都要有人全天候看守,在不同的宫殿安排看守所需的费用不同. 可是xuzhenyi手上的经费不足,无论如何也没法在每个宫殿都安置留守侍卫. 帮助xuzhenyi布置侍卫,在看守全部宫殿的前提下,使得花费的经费最少. 格式 输入格式 输入文件中数据表示一棵树,描述如下: 第1行 n

[Swust OJ 402]--皇宫看守(树形dp)

题目链接:http://acm.swust.edu.cn/problem/402/ Time limit(ms): 5000 Memory limit(kb): 65535 Description 太平王世子事件后,陆小凤成了皇上特聘的御前一品侍卫.  皇宫以午门为起点,直到后宫嫔妃们的寝宫,呈一棵树的形状:某些宫殿间可以互相望见.大内保卫森严,三步一岗,五步一哨,每个宫殿都要有人全天候看守,在不同的宫殿安排看守所需的费用不同.  可是陆小凤手上的经费不足,无论如何也没法在每个宫殿都安置留守侍卫

Vijos p1770 大内密探 树形DP+计数

4天终于做出来了,没错我就是这么蒟蒻.教训还是很多的. 建议大家以后编树形DP不要用记忆化搜索,回溯转移状态个人感觉更有条理性. 大神题解传送门 by iwtwiioi 我的题解大家可以看注释"//"部分 本题我用的树形DP中dp[x][fa][need]表示编号为x的节点的父亲选(1)没选(0),x的父亲需(1)不需要(0)其他节点来覆盖. 若父亲节点选了,则need肯定为0,所以不存在fa==1而need==1的状态,相当于浪费了¼的空间.毕竟数据范围比较小,而且程序要有可读性!程

HDU-2196 Computer (树形DP)

最近在看树形DP,这题应该是树形DP的经典题了,写完以后还是有点感觉的.之后看了discuss可以用树分治来做,以后再试一试. 题目大意 找到带权树上离每个点的最远点.︿( ̄︶ ̄)︿ 题解: 对于每一个点的最远点,就是以这个点为根到所有叶子节点的最长距离.但是如果确定根的话,除了根节点外,只能找到每个节点(度数-1)个子树的最大值,剩下一个子树是该节点当前的父亲节点. 所以当前节点的最远点在当前节点子树的所有叶子节点以及父亲节点的最远点上(当父亲节点的最远点不在当前节点的子树上时), 如果父亲节

UVA-01220 Party at Hali-Bula (树形DP+map)

题目链接:https://vjudge.net/problem/UVA-1220 思路: 树形DP模板题,求最大人数很简单,难点在于如何判断最大人数的名单是否有不同的情况: 解决方法是用一个数组f[manx][2]记录该节点是否出场的情况,为真时代表有多种情况; 具体讨论: 当父节点的值加上某个子节点的值时,他的f的情况也和该子节点一样: 当某个节点dp(i, 0) == dp(i, 1), 则该节点以及它的父节点也一定有多种情况(父节点必定取其中之一). Code: 1 #include<bi

HDU 1520 树形dp裸题

1.HDU 1520  Anniversary party 2.总结:第一道树形dp,有点纠结 题意:公司聚会,员工与直接上司不能同时来,求最大权值和 #include<iostream> #include<cstring> #include<cmath> #include<queue> #include<algorithm> #include<cstdio> #define max(a,b) a>b?a:b using nam

HDU2196 Computer(树形DP)

和LightOJ1257一样,之前我用了树分治写了.其实原来这题是道经典的树形DP,感觉这个DP不简单.. dp[0][u]表示以u为根的子树中的结点与u的最远距离 dp[1][u]表示以u为根的子树中的结点与u的次远距离 这两个可以一遍dfs通过儿子结点转移得到.显然dp[0][u]就是u的一个可能的答案,即u往下走的最远距离,还缺一部分就是u往上走的最远距离: dp[2][u]表示u往上走的最远距离 对于这个的转移,分两种情况,是这样的: dp[2][v] = max( dp[0][u]+w