题目链接
题面链接
题意
给定一个无向图,你需要从11点出发到达点,你在每一点的时候,使用11个单位的代价,随机得到相邻点的票,但是你可以选择留在原地,也可以选择使用掉这张票,问到达点的最小代价的方案的期望是多少。
题解
我们先假定在最优方案下从每个点xx出发,到达点的代价的期望为exex,那么显然,我们可以列出方程ex=∑min(ex,ey)degx+1ex=∑min(ex,ey)degx+1,其中yy与节点相连。初值dpn=0dpn=0。
借鉴GXZlegendGXZlegend的一句话,遇见“初始值只有一个点的dpdp值确定,其他点的dpdp值依赖于已经计算出来的点的dpdp值”这种类型的题,往往考虑使用最短路的方式转移。
观察方程,如果我们按照计算出来的exex从小到大的方式遍历的话,那么先计算出来的exex一定不会再被后计算出来的值更新,满足跟最短路一样的性质。
我们一开始假定所有的ex|x!=n=infex|x!=n=inf,并且en=0en=0,每个点的min(ex,ey)min(ex,ey)都取exex。
那么我们模拟一下这个转移过程,当前从堆里取出的点是uu,相邻的点有,我们发现vv是第一次被更新,因为,满足ev>euev>eu,那么vv就要被更新,即根据方程,那么ev=eu+degvev=eu+degv。
如果接下来某次取出的点是pp,相邻的点还有,并且ev>epev>ep,那么evev就要被二次更新了,也就是ev=(degv−2)ev+eu+epdegv+1ev=(degv−2)ev+eu+epdegv+1,那么ev=eu+ep+degv2ev=eu+ep+degv2。依次类推。
代码
#include <iostream>
#include <queue>
#include <vector>
using namespace std;
const int maxn = 300007;
const double inf = 1e9;
int n,m;
vector<int> G[maxn];
typedef pair<double,int> pii;
priority_queue<pii,vector<pii>,greater<pii> > Q;
double dp[maxn];
int deg[maxn],vis[maxn];
int usedeg[maxn];
void dij(){for(int i = 1;i < n;++i) dp[i] = inf;Q.push({0,n});vis[n] = 1;while(!Q.empty()){pii p = Q.top();Q.pop();int u = p.second;double nowdp = p.first;if(nowdp > dp[u]) continue;for(int v:G[u]){if(!vis[v]){vis[v] = 1;usedeg[v] = 1;dp[v] = nowdp+deg[v];Q.push({dp[v],v});}else if(nowdp < dp[v]){double c = dp[v]*usedeg[v]-deg[v];usedeg[v]++;dp[v] = (c+nowdp+deg[v])/usedeg[v];Q.push({dp[v],v});}}}
}int main(){cin>>n>>m;for(int i = 0;i < m;++i){int u,v;scanf("%d%d",&u,&v);G[u].push_back(v);G[v].push_back(u);deg[u] ++,deg[v] ++;}dij();printf("%.12lf\n",dp[1]);}