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 }