★【树型动态规划】【NOI2008】奥运物流
来源:互联网 发布:select in sql值太多 编辑:程序博客网 时间:2024/05/22 05:08
【问题描述】 2008 北京奥运会即将开幕,举国上下都在为这一盛事做好准备。为了高效率、成功地举办奥运会,对物流系统进行规划是必不可少的。 物流系统由若干物流基站组成,以 1...N 进行编号。每个物流基站 i 都有且仅有一个后继基站 Si,而可以有多个前驱基站。基站 i 中需要继续运输的物资都将被运往后继基站 Si,显然一个物流基站的后继基站不能是其本身。编号为 1 的从任何物流基站都可将物资运往控制基站。 物流基站称为控制基站,注意控制基站也有后继基站,以便在需要时进行物资的流通。在物流系统中,高可靠性与低成本是主要设计目。对于基站 i,我们定义其“可靠性” R (i ) 如下: 设物流基站 i 有 w 个前驱基站 P1, P2, Pw,即这些基站以 i 为后继基站,则基站 i 的可靠性 R(i)满足下式:
其中 Ci 和 k 都是常实数且恒为正,且有 k 小于 1。 整个系统的可靠性与控制基站的可靠性正相关,我们的目标是通过修改物流系统,即更改某些基站的后继基站,使得控制基站的可靠性 R(1)尽量大。但由于经费限制,最多只能修改 m 个基站的后继基站,并且,控制基站的后继基站不可被修改。因而我们所面临的问题就是,如何修改不超过 m 个基站的后继,使得控制基站的可靠性 R(1)最大化。 【输入格式】 输入文件 trans.in 第一行包含两个整数与一个实数,N, m, k。其中 N 表示基站数目,m 表示最多可修改的后继基站数目,k 分别为可靠性定义中的常数。 第二行包含 N 个整数,分别是 S1, S2...SN,即每一个基站的后继基站编号。 第三行包含 N 个正实数,分别是 C1, C2...CN,为可靠性定义中的常数。 【输出格式】 输出文件 trans.out 仅包含一个实数,为可得到的最大 R(1)。精确到小数点两位。 【输入样例】 4 1 0.5 2 3 1 3 10.0 10.0 10.0 10.0 【输出样例】 30.00 【样例说明】 原有物流系统如左图所示,4 个物流基站的可靠性依次为 22.8571,21.4286, 25.7143,10。
最优方案为将 2 号基站的后继基站改为 1 号,如右图所示。 此时 4 个基站的可靠性依次为 30,25,15,10。 【数据规模和约定】 本题的数据,具有如下分布:
对于所有的数据,满足 m ≤ N ≤ 60,Ci ≤ 106,0.3 ≤ k < 1,请使用双精度实数,无需考虑由此带来的误差。考试的时候,直接没管这道题,于是0分,后来听说贪心能得70分,很无语……
整个图就是一棵树,树根上是一个环,若设环的长度为len,那么整个答案为:
那么每个点离根越近答案越优,于是m次修改一定是将其中m个点的后继基站改为1。
用树型动态规划解决此问题:
首先枚举根部的环的长度,对每一个长度的环都进行一次动态规划,取出所有的最大值(注意修改环的长度可能会造成一次修改机会的消耗)作为最终答案。
用f[u][c][d]表示以u为根的子树中,修改c次,且u到根的距离为d的最大值(所有子树均不考虑1的后继边)。
对于非1的u,转移方程如下:
可以令g[u][c][d] = max{f[u][c][d + 1], f[u][c][1]}以简化方程,
并且可以发现右边的两项其实就是对c的一个最大分配,所以可以用多重背包问题解决。
但要注意u = 1时,方程右边只有第一项,并且其中的g[u][c][d]为f[u][c][1]。
代码:
/**************************\ * @prob: NOI2008 trans * * @auth: Wang Junji * * @stat: Accepted. * * @date: May. 21st, 2012 * * @memo: 树型动态规划 *\**************************/#include <cstdio>#include <cstdlib>#include <algorithm>#include <cstring>#include <string>const int maxN = 80;double f[maxN][maxN][maxN], g[maxN][maxN][maxN];double C[maxN], F[maxN], K[maxN], ans;int pre[maxN], n, m;void Dp(int u, int d){ for (int v = 2; v < n + 1; ++v) if (pre[v] == u) Dp(v, d + 1); for (int _d = std::min(2, d); _d < d + 1; ++_d) //由于当前的d值可能被修改过(有可能它的每一个祖先 //被指向了1),所以从2开始枚举d。 //(特别地,d = 1时不可能被修改过。) { for (int j = 0; j < m + 1; ++j) F[j] = 0; for (int v = 2; v < n + 1; ++v) if (pre[v] == u) for (int j = m; j > -1; --j) for (int k = j; k > -1; --k) F[j] = std::max(F[j], F[k] + g[v][j - k][_d]); //对其各个子树进行多重背包。 for (int j = 0; j < m + 1; ++j) f[u][j][_d] = F[j] + C[u] * K[_d]; } if (d > 1) //d > 1时,将其后继结点修改为1才有意义。 { for (int j = 0; j < m + 1; ++j) F[j] = 0; for (int v = 2; v < n + 1; ++v) if (pre[v] == u) for (int j = m; j > -1; --j) for (int k = j; k > -1; --k) F[j] = std::max(F[j], F[k] + g[v][j - k][1]); for (int j = 1; j < m + 1; ++j) f[u][j][1] = F[j - 1] + C[u] * K[1]; } for (int j = 0; j < m + 1; ++j) for (int _d = 0; _d < d; ++_d) g[u][j][_d] = std::max(f[u][j][_d + 1], f[u][j][1]); return;}int main(){ freopen("trans.in", "r", stdin); freopen("trans.out", "w", stdout); scanf("%d%d%lf", &n, &m, K + 1); for (int i = 2; i < n + 1; ++i) K[i] = K[i - 1] * K[1]; for (int i = 1; i < n + 1; ++i) scanf("%d", pre + i); for (int i = 1; i < n + 1; ++i) scanf("%lf", C + i); for (int ths = pre[1], len = 2; ths - 1; ths = pre[ths], ++len) //尝试分别将每一个处在环上的结点的父结点修改成1, //然后分别做一次动态规划。 { for (int i = 1; i < n + 1; ++i) for (int j = 0; j < m + 1; ++j) for (int k = 0; k < n + 1; ++k) f[i][j][k] = g[i][j][k] = 0; int tmp = pre[ths]; double Now = 0; pre[ths] = 1; for (int v = 2; v < n + 1; ++v) if (pre[v] == 1) Dp(v, 1); for (int j = 0; j < m + 1; ++j) F[j] = 0; for (int v = 2; v < n + 1; ++v) if (pre[v] == 1) for (int j = m; j > -1; --j) for (int k = j; k > -1; --k) F[j] = std::max(F[j], F[k] + f[v][j - k][1]); //由于1的直接子结点不可能被修改过, //所以上面只能为f[v][j - k][1]不能为g[v][j - k][1]。 for (int j = 0; j < m; ++j) Now = std::max(Now, F[j]); if (tmp == 1) Now = std::max(Now, F[m]); //若ths的父结点本身就是1,说明剩余的子树可以用m次修改机会。 ans = std::max(ans, (Now + C[1]) / (1 - K[len])); pre[ths] = tmp; //将ths的父结点还原。 } printf("%.2lf\n", ans); return 0;}
- ★【树型动态规划】【NOI2008】奥运物流
- BZOJ1065奥运物流 NOI2008
- BZOJ1065: [NOI2008]奥运物流
- BZOJ 1065: [NOI2008]奥运物流
- 【树型动态规划】【NOI2008】设计路线
- BZOJ1003 [ZJOI2006]物流运输trans(集合型动态规划)
- 【动态规划】【RQ202】奥运火炬登珠峰
- 【动态规划】【RQ208】奥运火炬到厦门
- 【动态规划+二分】奥运大包围
- NOI 2008 奥运物流 trans
- 动态规划----树型动态规划
- BZOJ 1003 ZJOI2006 物流运输trans 动态规划+SPFA
- BZOJ 1003 ZJOI 2006 物流运输 动态规划+SPFA
- 【BZOJ1003】【ZJOI2006】物流运输trans 最短路预处理+动态规划
- 【动态规划】【最短路】[BZOJ 1003]物流运输trans
- BZOJ 1003 物流运输【最短路】【动态规划】
- bzoj 1003: [ZJOI2006]物流运输 动态规划+最短路
- 【bzoj1003】【ZJOI2006】【物流运输】【最短路】【动态规划】
- How can I use Microsoft Visual C++ 2010 to create MEX files with MATLAB 7.10 (R2010a)?
- Excel操作快速手册
- 用一堆Gem来架起你的Rails3机枪
- CCNP-BSCI 002静态路由
- 从Windows到Mac的快速使用入门
- ★【树型动态规划】【NOI2008】奥运物流
- apt % dpkg
- 两岸快捷中,数据表处理总结
- opencv imread
- 2001-05-23
- 一些简单的js用法
- 控制textarea的长度
- rm % rmdir
- Alloy UI taglibs