• [省选练习]P


    [省选练习]Path:期望DP+Dijkstra

    题意

    (n,m leq 10^5)

    分析

    很有趣的一道题。

    (dis[x])为从(x)(n)的期望时间。

    题目中要求的最优策略,实际上就是只从(dis)大的地方向(dis)小的地方移动。

    所以,对于两个相邻的结点(x,y)(dis[x])能更新(dis[y])当且仅当(dis[x]<dis[y])

    我们希望所有更新(dis[x])(dis[y])从小到大,这样我们就能及时停止所有会使答案变差的更新。

    被确定的(dis[x])从小到大,很类似于Dijkstra算法的工作原理。

    类比优先队列优化的Dijkstra算法,我们每次取出队首元素,队首元素的(dis)此时被确定,不会再被其他结点更新,且每次取出的队首的(dis)一定单调不降。我们用取出的队首尝试更新其他未被确定的结点的(dis),并将更新成功的结点插入到优先队列中(事实上这里一定更新成功)。

    如何更新?

    有:

    [dis[x]=frac{m}{cnt[x]}+frac{sum[x]}{cnt[x]} ]

    更新一下(cnt[x])(sum[x]),通过上面的式子算出(dis[x])就好了。

    考场上把Dijkstra里的continue;敲成return;,华丽爆零。

    代码

    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <cmath>
    #include <cctype>
    #include <algorithm>
    #include <vector>
    #include <queue>
    #define rin(i,a,b) for(int i=(a);i<=(b);i++)
    #define rec(i,a,b) for(int i=(a);i>=(b);i--)
    #define trav(i,a) for(int i=head[(a)];i;i=e[i].nxt)
    typedef long long LL;
    using std::cin;
    using std::cout;
    using std::endl;
    
    inline int read(){
    	int x=0,f=1;char ch=getchar();
    	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
    	return x*f;
    }
    
    const int MAXN=100005;
    int n,m,ecnt,head[MAXN],cnt[MAXN];
    double dis[MAXN],sum[MAXN];
    bool vis[MAXN];
    struct Edge{
    	int to,nxt;
    }e[MAXN<<1];
    struct Pair{
    	int pos;
    	double dis;
    	inline friend bool operator > (Pair x,Pair y){
    		return x.dis>y.dis;
    	}
    };
    std::priority_queue<Pair,std::vector<Pair>,std::greater<Pair> > q;
    
    inline void add_edge(int bg,int ed){
    	ecnt++;
    	e[ecnt].to=ed;
    	e[ecnt].nxt=head[bg];
    	head[bg]=ecnt;
    }
    
    inline void dijkstra(){
    	rin(i,1,n) dis[i]=1e12;
    	while(!q.empty()) q.pop();
    	dis[n]=0;
    	q.push((Pair){n,0});
    	while(!q.empty()){
    		int x=q.top().pos;q.pop();
    		if(vis[x]) continue;
    		vis[x]=1;
    		trav(i,x){
    			int ver=e[i].to;
    			if(!vis[ver]&&dis[ver]>dis[x]){
    				sum[ver]+=dis[x];
    				cnt[ver]++;
    				dis[ver]=m*1.0/cnt[ver]+sum[ver]/cnt[ver];
    				q.push((Pair){ver,dis[ver]});
    			}
    		}
    	}
    }
    
    int main(){
    	freopen("path.in","r",stdin);
    	freopen("path.out","w",stdout);
    	n=read(),m=read();
    	rin(i,1,m){
    		int u=read(),v=read();
    		add_edge(u,v);
    		add_edge(v,u);
    	}
    	dijkstra();
    	printf("%.10lf
    ",dis[1]);
    	return 0;
    }
    
    /*
    4 4
    1 2
    2 4
    1 3
    3 4
    
    6.0000000000
    */
    
  • 相关阅读:
    第2课:关闭被黑客扫描的端口
    CentOS安装zip及用法
    网络安全目录
    第1课:电脑基础命令讲解
    SQL注入目录
    windows下安装redis
    CentOS安装rar及用法
    CentOS安装OpenOffice
    hadoop异常
    删除CentOS系统自带的jdk
  • 原文地址:https://www.cnblogs.com/ErkkiErkko/p/10176676.html
Copyright © 2020-2023  润新知