【SPOJ-TOMJERRY】Tom and Jerry【概率DP】【记忆化搜索】

就是NOI2005聪聪和可可。

论文题,见《浅析竞赛中一类数学期望问题的解决方法》


#include <cstdio>
#include <algorithm>

using namespace std;

const int maxn = 1005, maxq = 10000;

int n, m, head[maxn], cnt, p[maxn][maxn], dis[maxn], du[maxn], q[maxq];
double dp[maxn][maxn];

struct _edge {
	int v, next;
} g[maxn << 1];

inline int iread() {
	int f = 1, x = 0; char ch = getchar();
	for(; ch < '0' || ch > '9'; ch = getchar()) f = ch == '-' ? -1 : 1;
	for(; ch >= '0' && ch <= '9'; ch = getchar()) x = x * 10 + ch - '0';
	return f * x;
}

inline void add(int u, int v) {
	g[cnt] = (_edge) {v, head[u]};
	head[u] = cnt++;
}

void bfs(int x) {
	int h = 0, t = 0; q[t++] = x;
	for(int i = 1; i <= n; i++) dis[i] = -1;
	dis[x] = 0;

	while(h != t) {
		int u = q[h++];
		for(int i = head[u]; ~i; i = g[i].next)
			if(!~dis[g[i].v]) {
				dis[g[i].v] = dis[u] + 1;
				p[g[i].v][x] = u;
				q[t++] = g[i].v;
			} else if(dis[g[i].v] == dis[u] + 1) p[g[i].v][x] = min(p[g[i].v][x], u);
	}
}

double dfs(int u, int v) {
	if(dp[u][v] != -1) return dp[u][v];

	if(u == v) return dp[u][v] = 0.0;
	if(p[u][v] == v || p[p[u][v]][v] == v) return dp[u][v] = 1.0;

	double ans = dfs(p[p[u][v]][v], v);
	for(int i = head[v]; ~i; i = g[i].next) ans += dfs(p[p[u][v]][v], g[i].v);
	ans /= (du[v] + 1.0);
	ans += 1.0;
	return dp[u][v] = ans;
}

int main() {
	int T = iread();
	while(T--) {
		n = iread(); m = iread();
		for(int i = 1; i <= n; i++) {
			head[i] = -1, du[i] = 0; 
			for(int j = 1; j <= n; j++) p[i][j] = dp[i][j] = -1;
		}
		cnt = 0;

		int P = iread(), Q = iread();
		for(int i = 1; i <= m; i++) {
			int x = iread(), y = iread();
			du[x]++; du[y]++;
			add(x, y); add(y, x);
		}

		for(int i = 1; i <= n; i++) bfs(i);
		double ans = dfs(P, Q);
		printf("%.3lf\n", ans);
	}
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值