vijos1144.小胖守皇宫(树形DP)
2015-11-20 10:05
176 查看
一棵树有 N 个节点,现在需要将所有节点都看守住,如果我们选择了节点 i,那么节点
i 本身,节点 i 的父亲和儿子都会被看守住,每个节点有一个选择代价,求完成任务所需要的最小的代价。
显然这是一道树形DP。根据每个节点其实有只有三个状态:①被自己看守;②被儿子看守;③被父亲看守。我们设这三种状态分别为 F1,F2,F3。当然最终作为答案的根节点没有父亲就从
F1,F2 里面选小的。
接下来我们要考虑怎么转移。首先看 F1,我们规定
F1[ i ] 代表的是 i 节点被自己看守且以 i 为根的子树都已被看守的最小代价,也就是说一定会选择 i 节点自己,答案中必定会加入选择他自己的代价
Wi。因为这个点会被自己看管,所以只要考虑在其儿子的三个状态中选一个最小的,保证这个节点下面的子树都已被看守就行了。所以
F1[ i ] += min{ F1[ Si ], F2[ Si ], F3[ Si ] } + w[ i ],其中 Si
代表 i 节点的儿子。
接下来看 F2,我们规定 F2[ i ]
代表 i 节点被儿子看守且以 i 为根的子树都已被看守的最小代价,也就是说一定不选
i 节点,但是至少要在 i 节点的儿子中选择一个而且最多也就选一个,因为代价是正数,选一个就能把
i 看住,就不需要选择多余的点在增加代价了。因为 i 节点不能被选,所以只能在其儿子的
F1, F2 状态中选择小的( F3[ Si ] 代表选择 i 节点,所以不能用
F3[ Si ] ),来保证其子树都已被看守。所以 F2[ i ] += min{ F1[ Si ], F2[ Si ] } + t。t
代表选择一个儿子的最小代价:t = F1[ Si ] - min{ F1[ Si ], F2[ Si ] },顺便解释一下
t 的转移:我们从 Si 被看管的代价中选一个最小的,如果是 F1,那么说明
Si 已经被选,就不用再加 W[ Si ] 了,如果是 F2, 那么
F1 - F2 = W[ i ]。
最后看 F3,我们规定
F3[ i ] 代表 i 节点被父亲看守且以 i 为根的子树都已经被看守的最小代价,也就是说一定不选 i
节点和其儿子节点,必须选择他的父亲。因为必须选择父亲,那么 i 一定会被父亲看守,那么我们只要保证其下面的子树都已被看守,就是在儿子的
F1, F2 中选一个小的,因为还是不能选 i,所以其儿子的 F3 状态仍然不用考虑。所以
F3[ i ] += min{ F1[ Si ], F2[ Si ]}。
i 本身,节点 i 的父亲和儿子都会被看守住,每个节点有一个选择代价,求完成任务所需要的最小的代价。
显然这是一道树形DP。根据每个节点其实有只有三个状态:①被自己看守;②被儿子看守;③被父亲看守。我们设这三种状态分别为 F1,F2,F3。当然最终作为答案的根节点没有父亲就从
F1,F2 里面选小的。
接下来我们要考虑怎么转移。首先看 F1,我们规定
F1[ i ] 代表的是 i 节点被自己看守且以 i 为根的子树都已被看守的最小代价,也就是说一定会选择 i 节点自己,答案中必定会加入选择他自己的代价
Wi。因为这个点会被自己看管,所以只要考虑在其儿子的三个状态中选一个最小的,保证这个节点下面的子树都已被看守就行了。所以
F1[ i ] += min{ F1[ Si ], F2[ Si ], F3[ Si ] } + w[ i ],其中 Si
代表 i 节点的儿子。
接下来看 F2,我们规定 F2[ i ]
代表 i 节点被儿子看守且以 i 为根的子树都已被看守的最小代价,也就是说一定不选
i 节点,但是至少要在 i 节点的儿子中选择一个而且最多也就选一个,因为代价是正数,选一个就能把
i 看住,就不需要选择多余的点在增加代价了。因为 i 节点不能被选,所以只能在其儿子的
F1, F2 状态中选择小的( F3[ Si ] 代表选择 i 节点,所以不能用
F3[ Si ] ),来保证其子树都已被看守。所以 F2[ i ] += min{ F1[ Si ], F2[ Si ] } + t。t
代表选择一个儿子的最小代价:t = F1[ Si ] - min{ F1[ Si ], F2[ Si ] },顺便解释一下
t 的转移:我们从 Si 被看管的代价中选一个最小的,如果是 F1,那么说明
Si 已经被选,就不用再加 W[ Si ] 了,如果是 F2, 那么
F1 - F2 = W[ i ]。
最后看 F3,我们规定
F3[ i ] 代表 i 节点被父亲看守且以 i 为根的子树都已经被看守的最小代价,也就是说一定不选 i
节点和其儿子节点,必须选择他的父亲。因为必须选择父亲,那么 i 一定会被父亲看守,那么我们只要保证其下面的子树都已被看守,就是在儿子的
F1, F2 中选一个小的,因为还是不能选 i,所以其儿子的 F3 状态仍然不用考虑。所以
F3[ i ] += min{ F1[ Si ], F2[ Si ]}。
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int MAX_N = 1505; int n, num[MAX_N], w[MAX_N], s[MAX_N][MAX_N]; int g[MAX_N]; int f1[MAX_N], f2[MAX_N], f3[MAX_N]; void init() { scanf("%d", &n); for (int i = 1; i <= n; i ++){ int x; scanf("%d", &x); scanf("%d%d", &w[x], &num[x]); for (int j = 1; j <= num[x]; j ++){ int y; scanf("%d", &y); g[y] = x; s[x][j] = y; } } } void dfs(int x) { int p = 0x7fffffff; f1[x] = f2[x] = f3[x] = 0; for (int i = 1; i <= num[x]; i ++){ dfs(s[x][i]); f1[x] += min(f1[s[x][i]], min(f2[s[x][i]], f3[s[x][i]])); f2[x] += min(f1[s[x][i]], f2[s[x][i]]); int t = f1[s[x][i]] - min(f1[s[x][i]], f2[s[x][i]]); p = min(p, t); f3[x] += min(f1[s[x][i]], f2[s[x][i]]); } f2[x] += p; f1[x] += w[x]; } void doit() { memset(f1, 127, sizeof(f1)); memset(f2, 127, sizeof(f2)); memset(f3, 127, sizeof(f3)); int ans = 0; for (int i = 1; i <= n; i ++){ if (!g[i]){ dfs(i); ans += min(f1[i], f2[i]); } } printf("%d\n", ans); } int main() { init(); doit(); return 0; }
相关文章推荐
- 执行力
- Sublime Text 3 快捷键总结
- 一键删除.svn文件bat脚本
- 安装phpmyadmin
- jquery has deprecated synchronous XMLHTTPRequest
- Android USER 版本与ENG 版本的差异--MTK官方解释
- xcode7.1生成打包上传时需要注意的东西
- 常见行为:仿真&重力&碰撞&捕捉
- pid及socket文件丢失,数据库无法启动问题
- 跨线程调用问题
- chrome浏览器debugger 调试,有意思。
- linux --- mysql --- max_allowed_packet
- Apache+Tomcat负载均衡两种session共享方式的设置
- 如何在苹果手机上安装自制的AD证书
- 如何在苹果手机上安装自制的AD证书
- 如何在苹果手机上安装自制的AD证书
- 如何在苹果手机上安装自制的AD证书
- 11.20
- Tips for QRcode ( SAP中二维码相关)
- 网上销售平台--jersey实现应用服务器和图片服务器分离(六)