zoukankan      html  css  js  c++  java
  • ABC144_F Fork in the Road 期望DP

    # ABC144_F Fork in the Road 期望DP
    
    ## 题意
    
    有$N$个点,$M$条有向边,有向边表示$s_i -> t_i$,且满足$s_i < t_i$
    
    每到一个点会等概率得选择一条边移动
    
    在开始前会删除一条边(或者不删)来最小化到$n$的期望步数
    
    问移动到$N$号点的期望步数
    $$
    2leq Nleq600\
    N - 1leq M leq frac{N(N-1)}{2}
    $$
    
    
    ## 分析
    
    有一些显然的结论
    
    设$F[i]$表示从$i$号点走到$n$号点的期望步数,则有
    $$
    F[n] = 0\
    F[i] = avg(F[j]) + 1 (i,j)有边
    $$
    这样就构成方程组高斯消元即可
    
    注意到此题给出$s_i < t_i$
    
    即保证了总是从小点走到大点,因此可以直接DP
    
    那么删哪条边呢?
    
    从转移方程来看,我们显然希望删除掉最大的$F[j]$来最小化当前的期望,而此题的$n$比较小,因此不妨枚举删除$i$出发的边,贪心删除最大期望的边
    
    复杂度$O(n^2m)$
    
    ## 代码
    
    ```c++
    double dp[605];
    vector<int> e[maxn];
    int n,m;
     
    double cal(int x){
    	for(int i = n - 1;i >= 1;i--){
    		dp[i] = 1;
    		double mx = -1;
    		double t = 0;
    		for(auto v:e[i]){
    			if(dp[v] > mx) mx = dp[v],t = v;
    		}
    		if(i == x && e[i].size() != 1)
    		for(auto v:e[i]) {
    			if(v == t) continue;
    			dp[i] += dp[v] / (e[i].size() - 1);
    		} 
    		else
    		for(auto v:e[i])
    			dp[i] += dp[v] / e[i].size();
    	}
    	return dp[1];
    }
    
    int main(){
    	n = rd();
    	m = rd();
    	for(int i = 1;i <= m;i++){
    		int x = rd();
    		int y = rd();
    		e[x].push_back(y);
    	}
    	dp[n] = 0;
    	double ans = 1e18;
    	for(int i = 1;i < n;i++){
    		ans = min(ans,cal(i));
    	}
    	printf("%.10f",ans);
    }
    
  • 相关阅读:
    「CF1039D」You Are Given a Tree
    「NOIP2016」换教室
    「NOIP2014」飞扬的小鸟
    「AMPPZ2014」The Prices
    POj-3104 Drying 二分+贪心
    HDOJ1312<DFS>
    STL入门2
    HDU1425 <sort 快排>
    2304: Lights Out(枚举)
    1018:放苹果(递归)
  • 原文地址:https://www.cnblogs.com/hznumqf/p/14391129.html
Copyright © 2011-2022 走看看