zoukankan      html  css  js  c++  java
  • [bzoj3143][Hnoi2013]游走——动态规划+高斯消元

    题目大意:

    一个无向连通图,顶点从1编号到N,边从1编号到M。
    小Z在该图上进行随机游走,初始时小Z在1号顶点,每一步小Z以相等的概率随机选 择当前顶点的某条边,沿着这条边走到下一个顶点,获得等于这条边的编号的分数。当小Z 到达N号顶点时游走结束,总分为所有获得的分数之和。
    现在,请你对这M条边进行编号,使得小Z获得的总分的期望值最小。

    思路:

    由于我们需要确定每条边的权值,所以不妨将每条边期望意义下需要走的次数给求出来。

    先考虑每条边单独考虑的时候要怎么做,设(f_u)表示考虑第(j)条边的时候从(u)出发期望意义下还要走多少次(j)边,不难发现直接动态规划状态转移会有环,于是可以对于每一个点都列一个方程组,(n^3)高斯消元解出1号点的答案即可。

    但是每条边单独考虑的话,最多可能有(n^2)条边,那么时间复杂度就达到了(n^5),显然不是这样做。

    考虑将边的问题转化到点上面,我们求出每个点期望意义下经过多少次,那么每条边((u,v))期望意义下经过的次数就是(frac{f_u}{d_u}+frac{f_v}{d_v}),这样以后我们就只需要做一次(n^3)的高斯消元了。

    (f_{u})为点(u)期望意义下需要经过多少次:

    [f_{u}=sum_{v,v ot=n}frac{f_{v}}{d_v} ]

    当然1号点和(n)号点需要特殊考虑。

    /*=======================================
     * Author : ylsoi
     * Time : 2019.2.11
     * Problem : bzoj3143
     * E-mail : ylsoi@foxmail.com
     * ====================================*/
    #include<bits/stdc++.h>
     
    #define REP(i,a,b) for(int i=a,i##_end_=b;i<=i##_end_;++i)
    #define DREP(i,a,b) for(int i=a,i##_end_=b;i>=i##_end_;--i)
    #define debug(x) cout<<#x<<"="<<x<<" "
    #define fi first
    #define se second
    #define mk make_pair
    #define pb push_back
    typedef long long ll;
     
    using namespace std;
     
    void File(){
        freopen("bzoj3143.in","r",stdin);
        freopen("bzoj3143.out","w",stdout);
    }
     
    template<typename T>void read(T &_){
        _=0; T f=1; char c=getchar();
        for(;!isdigit(c);c=getchar())if(c=='-')f=-1;
        for(;isdigit(c);c=getchar())_=(_<<1)+(_<<3)+(c^'0');
        _*=f;
    }
     
    const int maxn=500+10;
    const double eps=1e-7;
    int n,m,d[maxn];
    int beg[maxn],to[maxn*maxn*2],las[maxn*maxn*2],cnte=1;
    double f[maxn][maxn],p[maxn],e[maxn*maxn],ans;
     
    void add(int u,int v){
        las[++cnte]=beg[u],beg[u]=cnte,to[cnte]=v;
        las[++cnte]=beg[v],beg[v]=cnte,to[cnte]=u;
    }
     
    void print(){
        REP(i,1,n){
            REP(j,1,n+1)printf("%lf ",f[i][j]);
            cout<<endl;
        }
        cout<<"====================================="<<endl;
    }
     
    void Gauss(){
        //print();
        REP(i,1,n-1){
            REP(j,i+1,n)if(fabs(f[j][i])>fabs(f[i][i]))swap(f[i],f[j]);
            REP(j,i+1,n){
                double t=f[j][i]/f[i][i];
                REP(k,i,n+1)f[j][k]=f[j][k]-f[i][k]*t;
            }
            //print();
        }
        DREP(i,n,1){
            p[i]=f[i][n+1]/f[i][i];
            REP(j,1,i-1)f[j][n+1]-=f[j][i]*p[i];
        }
        //REP(i,1,n)cout<<p[i]<<endl;
        //cout<<"================================"<<endl;
        REP(i,1,m){
            int u=to[i<<1],v=to[i<<1|1];
            e[i]=p[u]/d[u]*(u!=n)+p[v]/d[v]*(v!=n);
            //cout<<u<<" "<<v<<" "<<e[i]<<endl;
        }
    }
     
    int main(){
        //File();
        read(n),read(m);
        int u,v;
        REP(i,1,m)read(u),read(v),add(u,v),++d[u],++d[v];
        REP(i,1,n){
            f[i][i]=1;
            if(i==1 || i==n)f[i][n+1]=1;
            if(i==n)continue;
            for(int j=beg[i];j;j=las[j]){
                v=to[j];
                if(v==n)continue;
                f[i][v]=-1.0/d[v];
            }
        }
        Gauss();
        sort(e+1,e+m+1);
        REP(i,1,m)ans+=e[i]*(m-i+1);
        printf("%.3lf
    ",ans);
        return 0;
    }
    
  • 相关阅读:
    延迟消失菜单
    控制产品上下滚动
    百度音乐全选
    百度文库评分两种代码写法
    选项卡
    搜狐视频
    m 调用传参图片切换
    IIS 7.5站点配置
    jquery plugins —— datatables 搜索后汇总
    jquery plugins —— datatables 增加行号
  • 原文地址:https://www.cnblogs.com/ylsoi/p/10361586.html
Copyright © 2011-2022 走看看