zoukankan      html  css  js  c++  java
  • ●BZOJ 3143 [Hnoi2013]游走

    题链:

    http://www.lydsy.com/JudgeOnline/problem.php?id=3143
    题解:

    期望dp,高斯消元
    首先有这样一种贪心分配边的编号的方案:(然后我没想到,233)
    我们按每一条边的期望经过次数去分配编号,
    具体来说,就是期望经过次数越多的边,分配的编号越小,反之则编号越大。

    然后问题转化为如何求一条边的期望经过次数。(把求边的期望转化为求点的期望)
    我们定义cnt[i]表示i点的出度,dp[i]表示期望经过i点的次数。
    然后对于一个边(u,v),期望经过该边的次数为dp[u]/cnt[u]+dp[v]/cnt[v].
    特别的:当u或者v为N号点时,对边的期望贡献为0,因为到了N点就结束了。
    所以现在需要求出dp[i].
    由全期望公式$$dp[i]=sum_{j->i}dp[j]/cnt[j]$$
    特别的:
    1.j!=N,因为到达N点就已经结束游戏。
    2.当i==1时,dp[i]还要多加一个数值1,因为初始是就期望直接经过了1次。
    显然这个DP存在环,所以高斯消元解出dp值,然后再求出每一条边的期望经过次数,贪心地去编号即可。

    注:高斯消元判断系数是否为0时,要用到eps,否则可能因为精度问题而出错。


    代码:

    #include<bits/stdc++.h>
    #define MAXN 505
    using namespace std;
    const double eps=1e-7;
    struct EDGE{
    	int u,v; double exp;
    	bool operator < (const EDGE &rtm) const{
    		return exp>rtm.exp;
    	}
    }E[MAXN*MAXN];
    double a[MAXN][MAXN],dp[MAXN],ans;
    double *A[MAXN];
    bool Edge[MAXN][MAXN];
    int cnt[MAXN];
    int N,M;
    int dcmp(double x){
    	if(fabs(x)<=eps) return 0;
    	return x>0?1:-1;
    }
    void Gausselimination(int pos,int i){
    	if(pos==N+1||i==N+1) return;
    	for(int j=pos;j<=N;j++) if(dcmp(A[j][i])!=0){
    		swap(A[pos],A[j]); break;
    	}
    	if(dcmp(A[pos][i])!=0){
    		for(int j=pos+1;j<=N;j++){
    			double k=A[j][i]/A[pos][i];
    			for(int l=i;l<=N+1;l++)
    				A[j][l]-=A[pos][l]*k;
    		}
    	}
    	Gausselimination(pos+(dcmp(A[pos][i])!=0),i+1);
    	if(dcmp(A[pos][i])!=0){
    		for(int l=i+1;l<=N;l++)
    			dp[i]+=A[pos][l]*dp[l];
    		dp[i]=A[pos][N+1]-dp[i];
    		dp[i]=dp[i]/A[pos][i];
    	}
    }
    void buildequation(){
    	for(int i=1;i<=N;i++){
    		a[i][i]=-1;
    		if(i==1) a[i][N+1]=-1;
    		for(int j=1;j<N;j++){
    			if(!Edge[j][i]) continue;
    			a[i][j]=1.0/cnt[j];
    		}
    	}
    	for(int i=1;i<=N;i++) A[i]=a[i];
    }
    int main(){
    	scanf("%d%d",&N,&M);
    	for(int i=1,u,v;i<=M;i++){
    		scanf("%d%d",&u,&v);
    		E[i].u=u; E[i].v=v;
    		Edge[u][v]=Edge[v][u]=1;
    		cnt[u]++; cnt[v]++;
    	}
    	buildequation();
    	Gausselimination(1,1);
    	for(int i=1,u,v;i<=M;i++){
    		u=E[i].u; v=E[i].v;
    		E[i].exp=(u!=N?dp[u]/cnt[u]:0)+(v!=N?dp[v]/cnt[v]:0);
    	}
    	sort(E+1,E+M+1);
    	for(int i=1;i<=M;i++)
    		ans+=E[i].exp*i;
    	printf("%.3lf
    ",ans);
    	return 0;
    }
    

      

  • 相关阅读:
    Python之实现一个优先级队列
    java可变参数列表的实现
    static 关键字详解 static方法调用非static属性和方法
    this关键字详解
    vue自定义事件 子组件把数据传出去
    vue组件 Prop传递数据
    Vue 什么是组件
    vue v-model 表单控件绑定
    vue v-on监听事件
    vue v-if with v-for
  • 原文地址:https://www.cnblogs.com/zj75211/p/8541955.html
Copyright © 2011-2022 走看看