传送门:http://www.lydsy.com:808/JudgeOnline/problem.php?id=1415
水题没话说,预处理出两个点的最短路,再记忆化搜索就行了。
#include <iostream> #include <cstdio> #include <cstring> #include <list> #include <queue> using namespace std; #define INF 0x3f3f3f3f const int maxn = 1010; list <int> edge[maxn]; double f[maxn][maxn][2]; int dis[maxn][maxn]; int n, m, s, t; queue <int> q; void bfs(int x) { dis[x][x] = 0; q.push(x); while(!q.empty()) { int t = q.front(); q.pop(); for(list <int> :: iterator p = edge[t].begin(); p != edge[t].end(); p ++) { if(dis[x][t] + 1 < dis[x][*p]) { dis[x][*p] = dis[x][t] + 1; q.push(*p); } } } return; } int get(int x, int y) { int d = INF, ans = INF; for(list <int> :: iterator p = edge[x].begin(); p != edge[x].end(); p ++) { if(dis[*p][y] < d || (dis[*p][y] == d && *p < ans)) { d = dis[*p][y]; ans = *p; } } return ans; } double dp(int x, int y, int l) { if(f[x][y][l] != -1) return f[x][y][l]; if(x == y) return 0; if(l) { int nxt = get(x, y); if(nxt != y) nxt = get(nxt, y); f[x][y][l] = dp(nxt, y, 0) + 1; } else { double res = 0, cnt = 0; for(list <int> :: iterator p = edge[y].begin(); p != edge[y].end(); p ++) { res += dp(x, *p, 1); cnt += 1; } res += dp(x, y, 1); cnt += 1; f[x][y][l] = res / cnt; } return f[x][y][l]; } int main() { scanf("%d%d", &n, &m); scanf("%d%d", &s, &t); int u, v; for(int i = 1; i <= m; i ++) { scanf("%d%d", &u, &v); edge[u].push_back(v); edge[v].push_back(u); } memset(dis, 0x3f, sizeof(dis)); for(int i = 1; i <= n; i ++) { bfs(i); } for(int i = 0; i < maxn; i ++) { for(int j = 0; j < maxn; j ++) { for(int k = 0; k < 2; k ++) { f[i][j][k] = -1; } } } printf("%.3lf\n", dp(s, t, 1)); return 0; }