修仙录4.2 最终章

打题不细心
最后喜爆零


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]=m1j=1nmin(f[i],f[j])+1
s u m sum sum表示在这次转移取min时共选了多少次 f [ j ] f[j] f[j]
对dp式子化简
m f [ i ] = ∑ f [ j ] &lt; f [ i ] f [ j ] + ( m − s u m ) f [ i ] + m mf[i]=\sum_{f[j]&lt;f[i]}f[j]+(m-sum)f[i]+m mf[i]=f[j]<f[i]f[j]+(msum)f[i]+m

f [ i ] = ∑ f [ j ] + m s u m f[i]=\frac{\sum f[j]+m}{sum} f[i]=sumf[j]+m
那么现在考虑一个 k 如果要加入 i
显然 ∑ f [ j ] + m s u m &gt; ∑ f [ j ] + m + f [ k ] s u m + 1 \frac{\sum f[j]+m}{sum}&gt;\frac{\sum f[j]+m+f[k]}{sum+1} sumf[j]+m>sum+1f[j]+m+f[k]

化简 ∑ f [ j ] + m s u m &gt; f [ k ] \frac{\sum f[j]+m}{sum}&gt;f[k] sumf[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;
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值