題目鏈接:https://codeforces.com/gym/101620
題意:你需要乘車從點去點,你在每個點花費一塊錢可以買車票,售票機會隨機給你吐出一個相鄰車站的車票,你可選擇坐車走也可以選擇丟棄這張票再繼續買。你知道這個圖的形狀,那麼你預測你最少花費多少錢可以到達點。
解題心得:
- 真的好難啊,就這個題來說設爲從點到達點預計花費的最少錢,那麼在這個狀態下爲已知狀態,期望從已知到未知進行轉移。當我到達未知點的時候如果的度爲且周圍都是已知點,設點的到達點的期望爲,這個時候轉移方程式爲,對於這個公式的理解可以看作我從當前點隨機走到已知點再從已知點到點的最小期望。
- 但是上面公式是點周圍的已知點都已經得到,其實更進一步可以想到,也就說我即使得到了一個點不是最小期望,我也可以從周圍的點來進行更新得到更小的花費,這個更新花費的思路其實就是一個。
- 根據以上公式當有時可以更新,此時,這個公式可以看作我買了一張票這個張票經過的時候可以得到更小的答案,然後計算剛好經過的概率,這個時候對於這個公式化簡得到,此後若又有,可以繼續更新,然後依次類推。
#include <bits/stdc++.h>
using namespace std;
const int maxn = 3e5+100;
const double INF = 1e9;
struct Node {
int useCnt, degree;
double sum, p;
}node[maxn];
int n, m;
vector <int> ve[maxn];
void init() {
scanf("%d%d", &n, &m);
for(int i=1;i<=m;i++) {
int a, b; scanf("%d%d",&a, &b);
ve[a].push_back(b);
ve[b].push_back(a);
node[a].p = INF;
node[b].p = INF;
node[a].degree++;
node[b].degree++;
}
}
void dij() {
node[n].useCnt = 1;
node[n].p = 0;
priority_queue <pair<double, int>, vector<pair<double, int>>, greater<pair<double, int>> > qu;
qu.push(make_pair(0.0, n));
while(!qu.empty()) {
pair<double, int> now = qu.top();
qu.pop();
int u = now.second;
double va = now.first;
if(va > node[u].p) continue;
for(int i=0;i<ve[u].size();i++) {
int v = ve[u][i];
if(node[v].useCnt == 0) {
node[v].sum = node[u].p;
node[v].p = node[u].p + node[v].degree;
node[v].useCnt = 1;
qu.push(make_pair(node[v].p, v));
} else if(va < node[v].p) {
node[v].useCnt ++;
node[v].sum += node[u].p;
node[v].p = (node[v].sum + node[v].degree) / node[v].useCnt;
qu.push(make_pair(node[v].p, v));
}
}
}
}
int main() {
// freopen("1.in.txt", "r", stdin);
init();
dij();
printf("%.9f\n", node[1].p);
}