BZOJ 1415 聰聰和可可 (Dijkstra預處理 + 期望DP + 記憶化搜尋)
阿新 • • 發佈:2018-10-31
任重而道遠
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; }