【概率动态规划】【NOI2005】聪聪和可可
来源:互联网 发布:配置linux网络设置的ip 编辑:程序博客网 时间:2024/05/17 09:03
Input数据的第1行为两个整数N和E,以空格分隔,分别表示森林中的景点数和连接相邻景点的路的条数。第2行包含两个整数C和M,以空格分隔,分别表示初始时聪聪和可可所在的景点的编号。接下来E行,每行两个整数,第i+2行的两个整数Ai和Bi表示景点Ai和景点Bi之间有一条路。所有的路都是无向的,即:如果能从A走到B,就可以从B走到A。输入保证任何两个景点之间不会有多于一条路直接相连,且聪聪和可可之间必有路直接或间接的相连。Output输出1个实数,四舍五入保留三位小数,表示平均多少个时间单位后聪聪会把可可吃掉。Sample Input【输入样例1】4 31 41 22 33 4【输入样例2】9 99 31 22 33 44 53 64 64 77 88 9Sample Output【输出样例1】1.500【输出样例2】2.167HINT【样例说明1】开始时,聪聪和可可分别在景点1和景点4。第一个时刻,聪聪先走,她向更靠近可可(景点4)的景点走动,走到景点2,然后走到景点3;假定忽略走路所花时间。可可后走,有两种可能:第一种是走到景点3,这样聪聪和可可到达同一个景点,可可被吃掉,步数为1,概率为 。第二种是停在景点4,不被吃掉。概率为 。到第二个时刻,聪聪向更靠近可可(景点4)的景点走动,只需要走一步即和可可在同一景点。因此这种情况下聪聪会在两步吃掉可可。所以平均的步数是1* +2* =1.5步。
对于所有的数据,1≤N,E≤1000。对于50%的数据,1≤N≤50。先用n次Spfa预处理出path[i][j],即从i到j的第一步应该走的结点。
设f[i][j]为从猫从第i个点,老鼠在第j个点时,猫抓住老鼠所需要的时间的期望。
则有:
f[i][j] = sum {f[path[path[i][j]][j]][j`] / (deg(j) + 1)} + 1
(deg(j)为第j个结点的度。)
代码:
/************************************\ * @prob: NOI2005 cchkk * * @auth: Wang Junji * * @stat: Accepted. * * @date: June. 2nd, 2012 * * @memo: 概率动态规划、Spfa预处理 *\************************************/#include <cstdio>#include <cstdlib>#include <algorithm>#include <cstring>#include <string>const int maxN = 1010, SIZE = 0xffff;const double zero = 1e-12;struct Edge{ int v; Edge *next; Edge() {} Edge(int v, Edge *next): v(v), next(next) {}} *edge[maxN], _edge[maxN], *tot = _edge; double f[maxN][maxN];int path[maxN][maxN], deg[maxN], n, m, S, T;inline void Spfa(int S){ static int q[SIZE + 1], dist[maxN]; static bool marked[maxN]; memset(dist, 0x3f, sizeof dist); dist[S] = 0; int f = 0, r = 0, u, v; Edge *p; for (marked[q[r++] = S] = 1; f - r;) for (p = edge[u = q[f++]], marked[u] = 0, f &= SIZE; p; p = p -> next) if (dist[u] + 1 < dist[v = p -> v] || (dist[u] + 1 == dist[v] && u < path[v][S])) { dist[v] = dist[u] + 1, path[v][S] = u; if (!marked[v = p -> v]) marked[q[r++] = v] = 1, r &= SIZE; } return;}void Dp(int S, int T){ if (S == T) {f[S][T] = 0; return;} if (f[S][T] > zero) return; int nxt = path[S][T]; if (nxt == T) {f[S][T] = 1; return;} //这里需要判断一下直接就能走到的情况。 nxt = path[nxt][T]; if (nxt == T) {f[S][T] = 1; return;} double ths = 0; for (Edge *p = edge[T]; p; p = p -> next) Dp(nxt, p -> v), ths += f[nxt][p -> v] / (deg[T] + 1); Dp(nxt, T); ths += f[nxt][T] / (deg[T] + 1); f[S][T] = ths + 1; return;}int main(){ freopen("cchkk.in", "r", stdin); freopen("cchkk.out", "w", stdout); scanf("%d%d%d%d", &n, &m, &S, &T); while (m--) { int u, v; scanf("%d%d", &u, &v); edge[u] = new (tot++) Edge(v, edge[u]); ++deg[u]; edge[v] = new (tot++) Edge(u, edge[v]); ++deg[v]; } for (int i = 1; i < n + 1; ++i) Spfa(i); Dp(S, T); printf("%.3lf\n", f[S][T]); return 0;}
再贴一个考试的时候写的骗分算法:
/***************************\ * @prob: NOI2005 cchkk * * @auth: Wang Junji * * @stat: WA: 40 * * @date: June. 5th, 2012 * * @memo: Spfa、Dfs *\***************************/#include <cstdio>#include <cstdlib>#include <algorithm>#include <cstring>#include <string>const int maxN = 1010, SIZE = 0xffff;struct Edge{ int v; Edge *next; Edge() {} Edge(int v, Edge *next): v(v), next(next) {}} *edge[maxN], _edge[maxN], *tot = _edge;double f[maxN][maxN], ans;int dist[maxN], deg[maxN], n, m, S, T;inline void Bfs(){ static int q[SIZE + 1]; static bool marked[maxN]; int f = 0, r = 0, u, v; Edge *p; for (marked[q[r++] = S] = 1; f - r;) for (p = edge[u = q[f++]], f &= SIZE; p; p = p -> next) if (!marked[v = p -> v]) dist[v] = dist[u] + 1, marked[q[r++] = v] = 1, r &= SIZE; for (int i = 1; i < n + 1; ++i) if (i - S) ++(--dist[i] >>= 1); return;}void Dp(int u, int step){ if (f[u][step] < 1e-7) return; if (step >= dist[u]) { ans += f[u][step] * dist[u]; return; } for (Edge *p = edge[u]; p; p = p -> next) { f[p -> v][step + 1] = f[u][step] / (deg[u] + 1); Dp(p -> v, step + 1); } f[u][step + 1] = f[u][step] / (deg[u] + 1); Dp(u, step + 1); return;}int main(){ freopen("cchkk.in", "r", stdin); freopen("cchkk.out", "w", stdout); scanf("%d%d%d%d", &n, &m, &S, &T); while (m--) { int u, v; scanf("%d%d", &u, &v); edge[u] = new (tot++) Edge(v, edge[u]); edge[v] = new (tot++) Edge(u, edge[v]); ++deg[u]; ++deg[v]; } Bfs(); if (dist[T] <= 1) { printf("%.3lf\n", (double)(S != T)); return 0; } f[T][1] = 1; Dp(T, 1); printf("%.3lf\n", ans); return 0;}/*贪心,首先算出猫从初始位置走到所有点需要的时间,然后假定猫在最后追到老鼠的时候走的一定是最短路径(即不存在猫追老鼠兜圈子的情况),这样做可以得40分。*/
- 【概率动态规划】【NOI2005】聪聪和可可
- 【NOI2005】【概率动态规划】聪聪和可可
- BZOJ 1415: [Noi2005]聪聪和可可|概率dp
- BZOJ 1415 [Noi2005]聪聪和可可【概率dp】
- bzoj 1415 [Noi2005]聪聪和可可 概率dp
- [BZOJ1415][NOI2005]聪聪和可可-概率与期望
- bzoj1415 [Noi2005]聪聪和可可 (概率与期望)
- [Noi2005]聪聪和可可
- [Noi2005]聪聪和可可
- NOI2005 : 聪聪和可可
- NOI2005 聪聪和可可
- BZOJ 1415|NOI 2005|聪聪和可可|概率期望|动态规划
- BZOJ1415 [Noi2005]聪聪和可可
- 1415: [Noi2005]聪聪和可可
- 【BZOJ 1415】 [Noi2005]聪聪和可可
- BZOJ 1415: [Noi2005]聪聪和可可
- bzoj1415【NOI2005】聪聪和可可
- BZOJ1415: [Noi2005]聪聪和可可
- 6_5_天天向上
- Windows xp 带用户名密码的自动登录问题(已解决)
- 【整理】linux下测试RTC驱动相关的命令date和hwclock常见用法简介
- 4G全城体验
- 定时上报GPS坐标信息至服务器
- 【概率动态规划】【NOI2005】聪聪和可可
- 获取Android各种系统信息
- C++ GUI Qt4学习笔记(三)
- Sql Server 删除数据表的存储过程,直接能用!(源码带说明)
- C# 常用属性
- 用接口实现通过改外部文件实现判断调用接口内的方法
- 建筑与软件开发
- 设计模式大集锦 程序员面试全攻略
- 超级详细Tcpdump 的用法