1. 程式人生 > >BZOJ 1415 聰聰和可可 (Dijkstra預處理 + 期望DP + 記憶化搜尋)

BZOJ 1415 聰聰和可可 (Dijkstra預處理 + 期望DP + 記憶化搜尋)

任重而道遠

Input

資料的第1行為兩個整數N和E,以空格分隔,分別表示森林中的景點數和連線相鄰景點的路的條數。 第2行包含兩個整數C和M,以空格分隔,分別表示初始時聰聰和可可所在的景點的編號。 接下來E行,每行兩個整數,第i+2行的兩個整數Ai和Bi表示景點Ai和景點Bi之間有一條路。 所有的路都是無向的,即:如果能從A走到B,就可以從B走到A。 輸入保證任何兩個景點之間不會有多於一條路直接相連,且聰聰和可可之間必有路直接或間接的相連。

Output

輸出1個實數,四捨五入保留三位小數,表示平均多少個時間單位後聰聰會把可可吃掉。

Sample Input

【輸入樣例1】 4 3 1 4 1 2 2 3 3 4 【輸入樣例2】 9 9 9 3 1 2 2 3 3 4 4 5 3 6 4 6 4 7 7 8 8 9

Sample Output

【輸出樣例1】 1.500 【輸出樣例2】 2.167

Hint

【樣例說明1】
開始時,聰聰和可可分別在景點1和景點4。
第一個時刻,聰聰先走,她向更靠近可可(景點4)的景點走動,走到景點2,然後走到景點3;假定忽略走路所花時間。
可可後走,有兩種可能:
第一種是走到景點3,這樣聰聰和可可到達同一個景點,可可被吃掉,步數為1,概率為 。
第二種是停在景點4,不被吃掉。概率為 。
到第二個時刻,聰聰向更靠近可可(景點4)的景點走動,只需要走一步即和可可在同一景點。因此這種情況下聰聰會在兩步吃掉可可。
所以平均的步數是1* +2* =1.5步。


對於所有的資料,1≤N,E≤1000。
對於50%的資料,1≤N≤50。

AC程式碼:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;

const int N = 1e3 + 5;
struct Edge {
	int tov, nxt;
}e[N << 1];
struct Node {
	int id, d;
	bool operator < (const Node &nd) const {
		return d < nd.d;
	}
};
priority_queue <Node> q;
int head[N], dis[N][N], w[N][N], vis[N][N], du[N];
int n, m, num, s, t;
double dp[N][N];
double sww;

void add_edge (int u, int v) {
	e[++num] = (Edge) {v, head[u]}, head[u] = num;
}

void Dijkstra (int x) {
	memset (dis[x], 127, sizeof (dis[x]));
	memset (w[x], 127, sizeof (w[x]));
	dis[x][x] = 0;
	q.push ((Node) {x, dis[x][x]});
	while (!q.empty ()) {
		Node nd = q.top (); q.pop ();
		int u = nd.id, d = nd.d;
		if (dis[x][u] != d) continue;
		for (int i = head[u]; i; i = e[i].nxt) {
			int v = e[i].tov;
			if (dis[x][v] > dis[x][u] + 1) {
				dis[x][v] = dis[x][u] + 1;
				q.push ((Node) {v, dis[x][v]});
			}
		}
	}
}

double dfs (int u, int v) {
	if (vis[u][v]) return dp[u][v];
	if (u == v) return 0;
	int fir = w[u][v], sec = w[fir][v];
	if (fir == v || sec == v) return 1;
	dp[u][v] = 1;
	for (int i = head[v]; i; i = e[i].nxt) {
		int x = e[i].tov;
		dp[u][v] += dfs (sec, x) / (du[v] + 1);
	}
	dp[u][v] += dfs (sec, v) / (du[v] + 1);
	vis[u][v] = 1;
	return dp[u][v];
}

void init () {
	for (int i = 1; i <= n; i++)
		Dijkstra (i);
	for (int i = 1; i <= n; i++)
		for (int it = head[i]; it; it = e[it].nxt) {
			int x = e[it].tov;
			for (int j = 1; j <= n; j++)
				if (dis[i][j] == dis[x][j] + 1) w[i][j] = min (w[i][j], x);
		}
}

int main () {
	scanf ("%d%d", &n, &m);
	scanf ("%d%d", &s, &t);
	for (int i = 1; i <= m; i++) {
		int u, v;
		scanf ("%d%d", &u, &v);
		add_edge (u, v), du[u]++;
		add_edge (v, u), du[v]++;
	}
	init ();
	sww = dfs (s, t);
	printf ("%.3lf", sww);
	return 0;
}