打题不细心
最后喜爆零
jzoj 6101 Path
https://jzoj.net/senior/#main/show/6101
期望dp。
相当于每天m种情况,每次选择期望更小的方法(不走还是走)
于是:
f
[
i
]
=
1
m
∑
j
=
1
n
m
i
n
(
f
[
i
]
,
f
[
j
]
)
+
1
f[i]=\frac{1}{m}\sum_{j=1}^nmin(f[i],f[j])+1
f[i]=m1∑j=1nmin(f[i],f[j])+1
设
s
u
m
sum
sum表示在这次转移取min时共选了多少次
f
[
j
]
f[j]
f[j]
对dp式子化简
m
f
[
i
]
=
∑
f
[
j
]
<
f
[
i
]
f
[
j
]
+
(
m
−
s
u
m
)
f
[
i
]
+
m
mf[i]=\sum_{f[j]<f[i]}f[j]+(m-sum)f[i]+m
mf[i]=∑f[j]<f[i]f[j]+(m−sum)f[i]+m
f
[
i
]
=
∑
f
[
j
]
+
m
s
u
m
f[i]=\frac{\sum f[j]+m}{sum}
f[i]=sum∑f[j]+m
那么现在考虑一个 k 如果要加入 i
显然
∑
f
[
j
]
+
m
s
u
m
>
∑
f
[
j
]
+
m
+
f
[
k
]
s
u
m
+
1
\frac{\sum f[j]+m}{sum}>\frac{\sum f[j]+m+f[k]}{sum+1}
sum∑f[j]+m>sum+1∑f[j]+m+f[k]
化简 ∑ f [ j ] + m s u m > f [ k ] \frac{\sum f[j]+m}{sum}>f[k] sum∑f[j]+m>f[k]
看成是松弛操作。跑dijstra就好
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
using namespace std;
const int MAXN=1e5+5;
int n,m,sum[MAXN];
int head[MAXN],next[MAXN*2],to[MAXN*2],cnt;
double f[MAXN];
struct node{
int x,sum;
double val;
node(){x=sum=val=0;}
node(int x,int sum,double val):x(x),sum(sum),val(val){}
friend bool operator < (node a,node b){
return a.val*b.sum>b.val*a.sum;
}
};
priority_queue<node>q;
bool isv[MAXN];
void add(int u,int v){
next[++cnt]=head[u],to[cnt]=v,head[u]=cnt;
next[++cnt]=head[v],to[cnt]=u,head[v]=cnt;
}
double dijstra(){
sum[n]=1,q.push(node(n,1,0));
while(!q.empty()){
int x=q.top().x;q.pop();
if(isv[x]) continue;
isv[x]=1;
double now=(f[x]+m)/sum[x];
if(x==1) return now;
if(x==n) now=0;
for(int i=head[x];i;i=next[i]){
int y=to[i];
if(!sum[y]||f[y]+m>sum[y]*now){
f[y]+=now,sum[y]++;
if(!isv[y]) q.push(node(y,sum[y],f[y]+m));
}
}
}
}
int main(){
freopen("path.in","r",stdin);
freopen("path.out","w",stdout);
cin>>n>>m;
for(int i=1,u,v;i<=m;i++) scanf("%d%d",&u,&v),add(u,v);
printf("%.10lf",dijstra());
return 0;
}