BZOJ--1415(概率DP,记忆化搜索)

2014-12-30 09:47:39

思路:看论文写的一道题....(--<<浅析竞赛中一类数学期望问题的解决方法>> 汤可因)

  聪聪不断靠近可可,先通过N次广度优先搜索处理出p[][]数组,它的含义:若聪聪在 i,可可在 j,聪聪沿i->j的最短路下一步应该走的编号最小的点,存为p[i][j],由于聪聪一次至多可以走2步也就是走到p[p[i][j]][j]点。(这个过程需要维护一个最短路,并且维护编号)

  dp[i][j]表示从 i 到 j 的平均步数,d[i]表示 i 这个点的度数。

  若当前聪聪在 i,可可在 j,那么聪聪下一个位置在nextp = p[p[i][j]][j](当然如果p[i][j]已经抓到可可就不再走)。可可下一个位置可能在 j 的所有相邻点和 j 点自己,且概率均为 1 / (d[j] + 1)

  那么我们思考:计算dp[i][j]需要知道dp[nextp][neighbors of j , j],所以考虑用记忆化搜索,逐层逼近,直到聪聪能在一步内抓到可可。

  dp[i][j] = (Sima(dp[nextp][neighbors[k]]) + dp[nextp][j]) / (d[j] + 1) + 1。(因为聪聪要先走到nextp,所以最后要加1)

  对于当前dp[i][j],要先搜索dp[nextp][neihbors[k]],并累加,是个典型的记忆化搜索。

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <cstdlib>
  4 #include <cmath>
  5 #include <vector>
  6 #include <map>
  7 #include <set>
  8 #include <stack>
  9 #include <queue>
 10 #include <iostream>
 11 #include <algorithm>
 12 using namespace std;
 13 #define lp (p << 1)
 14 #define rp (p << 1|1)
 15 #define getmid(l,r) (l + (r - l) / 2)
 16 #define MP(a,b) make_pair(a,b)
 17 typedef long long ll;
 18 typedef unsigned long long ull;
 19 typedef pair<int,int> pii;
 20 const int INF = 1 << 30;
 21 const int maxn = 1010;
 22 
 23 int n,m,st,ed;
 24 int first[maxn],next[maxn << 1],ver[maxn << 1],ecnt;
 25 int p[maxn][maxn];
 26 double dp[maxn][maxn];
 27 
 28 void Init(){
 29     memset(first,-1,sizeof(first));
 30     memset(dp,-1,sizeof(dp));
 31     memset(p,0,sizeof(p));
 32     ecnt = 0;
 33 }
 34 
 35 void Add_edge(int u,int v){
 36     next[++ecnt] = first[u];
 37     ver[ecnt] = v;
 38     first[u] = ecnt;
 39 }
 40 
 41 void Bfs(int s){
 42     queue<pii> Q;
 43     int vis[maxn],dis[maxn];
 44     for(int i = 1; i <= n; ++i) dis[i] = INF;
 45     memset(vis,0,sizeof(vis));
 46     vis[s] = 1;
 47     dis[s] = 0;
 48     Q.push(MP(s,0));
 49     while(!Q.empty()){
 50         pii x = Q.front(); Q.pop();
 51         for(int i = first[x.first]; i != -1; i = next[i]){
 52             int v = ver[i];
 53             if(vis[v]){
 54                 if(dis[v] == dis[x.first] + 1 && x.second < p[s][v]){
 55                     p[s][v] = x.second;
 56                     Q.push(MP(v,p[s][v]));
 57                 }
 58                 continue;
 59             }
 60             dis[v] = dis[x.first] + 1;
 61             vis[v] = 1;
 62             pii tmp(v,v);
 63             if(x.second != 0) tmp.second = x.second;
 64             p[s][v] = tmp.second;
 65             Q.push(tmp);
 66         }
 67     }
 68 }
 69 
 70 void Dfs(int u,int w){
 71     if(dp[u][w] >= 0) return;
 72     if(p[u][w] == w || p[p[u][w]][w] == w){
 73         dp[u][w] = 1.0;
 74         return;
 75     }
 76     dp[u][w] = 0.0;
 77     if(u == w) return;
 78     int nextu = p[p[u][w]][w],d = 0;
 79     for(int i = first[w]; i != -1; i = next[i]){
 80         int v = ver[i];
 81         d++;
 82         Dfs(nextu,v);
 83         dp[u][w] += dp[nextu][v];
 84     }
 85     Dfs(nextu,w);
 86     dp[u][w] += dp[nextu][w];
 87     dp[u][w] = dp[u][w] / (d + 1.0) + 1.0;
 88 }
 89 
 90 void Solve(){
 91     for(int i = 1; i <= n; ++i)
 92         Bfs(i);
 93     Dfs(st,ed);
 94 }
 95 
 96 int main(){
 97     int a,b;
 98     while(scanf("%d%d",&n,&m) != EOF){
 99         scanf("%d%d",&st,&ed);
100         Init();
101         for(int i = 1; i <= m; ++i){
102             scanf("%d%d",&a,&b);
103             Add_edge(a,b);
104             Add_edge(b,a);
105         }
106         Solve();
107         printf("%.3f\n",dp[st][ed]);
108     }
109     return 0;
110 }

 

转载于:https://www.cnblogs.com/naturepengchen/articles/4192982.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值