[BZOJ1415] [NOI2005]聰聰和可可(期望DP)

題意

在一個魔法森林裏,住着一隻聰明的小貓聰聰和一隻可愛的小老鼠可可。雖 然灰姑娘非常喜歡她們倆,但是,聰聰終究是一隻貓,而可可終究是一隻老鼠, 同樣不變的是,聰聰成天想着要吃掉可可。

一天,聰聰意外得到了一臺非常有用的機器,據說是叫 GPS,對可可能準確 的定位。有了這臺機器,聰聰要吃可可就易如反掌了。於是,聰聰準備馬上出發, 去找可可。而可憐的可可還不知道大難即將臨頭,仍在森林裏無憂無慮的玩耍。 小兔子乖乖聽到這件事,馬上向灰姑娘報告。灰姑娘決定儘快阻止聰聰,拯救可 可,可她不知道還有沒有足夠的時間。

整個森林可以認爲是一個無向圖,圖中有 NNN 個美麗的景點,景點從 111NNN 編號。小動物們都只在景點休息、玩耍。在景點之間有一些路連接。

當聰聰得到 GPS 時,可可正在景點 MMM(M≤NM≤NMN)處。以後的每個時間單位,可可 都會選擇去相鄰的景點(可能有多個)中的一個或停留在原景點不動。而去這些地方所發生的概率是相等的。假設有 PPP 個景點與景點 M 相鄰,它們分別是景點 R、 景點 S,……景點 Q,在時刻 TTT 可可處在景點 M,則在( T+1 T+1 T+1 )時刻,可可有 1/(1+P)1/(1 +P)1/(1+P) 的可能在景點 R,有 1/(1+P)1/(1 +P)1/(1+P) 的可能在景點 S,……,有 1/(1+P)1/(1 +P)1/(1+P) 的可能在景點 Q,還有1/(1+P)1/(1 +P)1/(1+P)的可能停在景點 M

我們知道,聰聰是很聰明的,所以,當她在景點 C 時,她會選一個更靠近 可可的景點,如果這樣的景點有多個,她會選一個標號最小的景點。由於聰聰太 想吃掉可可了,如果走完第一步以後仍然沒吃到可可,她還可以在本段時間內再 向可可走近一步。

在每個時間單位,假設聰聰先走,可可後走。在某一時刻,若聰聰和可可位 於同一個景點,則可憐的可可就被吃掉了。

灰姑娘想知道,平均情況下,聰聰幾步就可能吃到可可。而你需要幫助灰姑 娘儘快的找到答案。

輸入輸出格式

輸入格式:

數據的第 1 行爲兩個整數 NNNEEE,以空格分隔,分別表示森林中的景點數和 連接相鄰景點的路的條數。

第 2 行包含兩個整數 CCCMMM,以空格分隔,分別表示初始時聰聰和可可所在的景點的編號。

接下來 E 行,每行兩個整數,第 i+2i+2i+2 行的兩個整數 AiA_iAiBiB_iBi表示景點 AiA_iAi和景點 BiB_iBi 之間有一條路。 所有的路都是無向的,即:如果能從 A 走到 B,就可以從 B 走到 A。

輸入保證任何兩個景點之間不會有多於一條路直接相連,且聰聰和可可之間必有路直接或間接的相連。

輸出格式:

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

輸入輸出樣例

輸入樣例#1: 複製
4 3 
1 4 
1 2 
2 3 
3 4
輸出樣例#1: 複製
1.500 
輸入樣例#2: 複製
9 9 
9 3 
1 2 
2 3 
3 4 
4 5 
3 6 
4 6 
4 7 
7 8 
8 9
輸出樣例#2: 複製
2.167

說明

【樣例說明 1】

開始時,聰聰和可可分別在景點 1 和景點 4。

第一個時刻,聰聰先走,她向更靠近可可(景點 4)的景點走動,走到景點 2, 然後走到景點 3;假定忽略走路所花時間。

可可後走,有兩種可能: 第一種是走到景點 3,這樣聰聰和可可到達同一個景點,可可被吃掉,步數爲 111,概率爲0.50.50.5

第二種是停在景點 4,不被吃掉。概率爲 0.50.50.5

到第二個時刻,聰聰向更靠近可可(景點 4)的景點走動,只需要走一步即和 可可在同一景點。因此這種情況下聰聰會在兩步吃掉可可。 所以平均的步數是 1×1/2+2×1/2=1.51\times 1/2 + 2\times 1/2 =1.51×1/2+2×1/2=1.5 步。

對於 50%的數據,1≤N≤501≤N≤501N50
對於所有的數據,1≤N,E≤10001≤N,E≤10001N,E1000

這個題是一個很經典的題,因爲數據範圍不大,我們可以預處理出從每一個點走向一個點第一步走的點,bfsbfs即可,然後設f[s][t]f[s][t],爲小貓在ss,老鼠在tt的答案,直接轉移就好了。

#include <bits/stdc++.h>

#define For(i, a, b) for (register int i = (a), i##_end = (b); i <= i##_end; ++ i) 
#define FOR(i, a, b) for (register int i = (a), i##_end = (b); i >= i##_end; -- i) 
#define pb push_back
#define ldb long double

using namespace std;

inline int read() {
    int _ = 0, ___ = 1, __ = getchar();
    for (; !isdigit(__); __ = getchar()) if (__ == '-') ___ = -1;
    for (; isdigit(__); __ = getchar()) _ = (_ << 3) + (_ << 1) + (__ ^ 48);
    return _ * ___;
}

const int N = 1e3 + 10;

int fst[N][N], n, m; 

ldb f[N][N]; vector<int> G[N]; 

void BFS(int s) {
    queue<int> q; 
    for (fst[s][s] = -1, q.push(s); !q.empty(); q.pop()) {
        int k = q.front();
        for (auto v : G[k]) if (!fst[s][v]) {
            q.push(v);
            if (k ^ s) fst[s][v] = fst[s][k];
            else fst[s][v] = v; 
        }
    }
    fst[s][s] = 0;
}

ldb dfs(int s, int t) {
    if (f[s][t]) return f[s][t];
    if (s == t) return 0;
    if (fst[s][t] == t) return 1; 
    if (fst[fst[s][t]][t] == t) return 1; 
    ldb res = 0, sz = G[t].size(); 
    for (auto v : G[t]) 
        res += (dfs(fst[fst[s][t]][t], v) + 1) / (sz + 1);
    res += (dfs(fst[fst[s][t]][t], t) + 1) / (sz + 1);
    return f[s][t] = res; 
}

int main() {
#ifdef ylsakioi
    freopen("4206.in", "r", stdin);
    freopen("4206.out", "w", stdout);
#endif

    int x, y, C, M; 

    n = read(), m = read(), C = read(), M = read();
    For(i, 1, m) x = read(), y = read(), G[x].pb(y), G[y].pb(x);
    For(i, 1, n) sort(G[i].begin(), G[i].end());
    For(i, 1, n) BFS(i);

    printf("%.3Lf", dfs(C, M));

    return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章