[BZOJ5197] [CERC2017]Gambling Guide
题目链接
https://www.lydsy.com/JudgeOnline/problem.php?id=5197
Solution
据说这种题有套路...但是窝不会...所以窝看了题解才知道做的...
首先这种期望题一般状态是(f_x)表示(x)到(n)的期望步数,由于要求最优策略,那么我们随机到一条边时从(f_x,f_v)里选一个最小的转移即可,具体的:
[f_x=frac{1}{d_x}sum_{vin son_x}(1+min(f_x,f_v))
]
其中(f_n=0)。
然后我么考虑从(n)号点开始更新其他的点,仿照( m Dijkstra)的形式。
我们假定一开始除了(n)号点以外其他的点(f_x=+infty),且每个(min)都选(f_x)。
那么设当前枚举到的点为(x),边为((x,v)),那么如果(f_vgeqslant f_x)时,(v)号点的(min)会改选为(f_x),那么我们更新一下(f_v)就好了。
显然这样更新满足每次选到的都是最小的点,而且他不会再被更新。
复杂度(O(nlog n))。
#include<bits/stdc++.h>
using namespace std;
void read(int &x) {
x=0;int f=1;char ch=getchar();
for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f;
for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f;
}
void print(int x) {
if(x<0) putchar('-'),x=-x;
if(!x) return ;print(x/10),putchar(x%10+48);
}
void write(int x) {if(!x) putchar('0');else print(x);putchar('
');}
#define lf double
#define ll long long
#define pii pair<int,int >
#define vec vector<int >
#define pb push_back
#define mp make_pair
#define fr first
#define sc second
#define FOR(i,l,r) for(int i=l,i##_r=r;i<=i##_r;i++)
const int maxn = 4e5+10;
const int inf = 1e9;
const lf eps = 1e-8;
const int mod = 1e9+7;
lf f[maxn],s[maxn];
int d[maxn],c[maxn],head[maxn],tot,n,m,vis[maxn];
struct edge{int to,nxt;}e[maxn<<1];
void ins(int u,int v) {e[++tot]=(edge){v,head[u]},head[u]=tot;}
priority_queue<pair<lf,int > > q;
int main() {
read(n),read(m);
for(int i=1,x,y;i<=m;i++) read(x),read(y),ins(x,y),ins(y,x),d[x]++,d[y]++;
memset(f,127,sizeof f);f[n]=0;
q.push(mp(0.0,n));
while(!q.empty()) {
int x=q.top().second;q.pop();
if(vis[x]) continue;vis[x]=1;
for(int v,i=head[x];i;i=e[i].nxt)
if(f[v=e[i].to]>=f[x])
c[v]++,s[v]+=f[x],f[v]=(s[v]+d[v])/(lf)c[v],q.push(mp(-f[v],v));
}printf("%.10lf
",f[1]);
return 0;
}