zoukankan      html  css  js  c++  java
  • BZOJ-3143/洛谷3232 游走(HNOI2013)概率DP

    题意:给定n个点m条边。每条边的权值还没决定,权值大小为从1到m。从1出发每次等概率选一条出边向下走,直到走到n点停止,路径代价就是边权总和。由你来决定边权来使得上诉路径代价期望值最小。

    解法:点这么少边这么多,比较容易想到我们先求出点的期望经过次数dp[i],那么对于一条边(u,v)它的期望经过次数就等于 (dp[u]/du[u]+dp[v]/du[v])。对于这个值排序之后贪心赋予边权大小即可。

    问题在于怎么得到每个点的期望经过次数呢?

    这里直接写状态转移方程  dp[u]=sigma(dp[v]/du[v]) + [u==1];(v表示出点,du表示度数)

    特别要注意几个点:

    ①为什么是du[v]而不是du[u]?因为此时算的是从1出发的  。②为什么u==1时候才加一,其实这个问题结果和上一个一样。 ③注意终点n不参与上诉的转移,为什么? 因为一旦到达终点n之后就不再游走了。

    代码如下:

    #include<bits/stdc++.h>
    using namespace std;
    const int N=500+10;
    const double eps=1e-6;
    int n,m,k;
    vector<int> G[N];
    struct edge{
        int x,y; double gx=0;
        bool operator < (const edge &rhs) const {
            return gx>rhs.gx;
        }
    }e[N*N];
    
    double c[N][N],b[N];
    void Gauss() {
        int r=0;
        for (int i=1;i<=n;i++) {
            int j=r+1;
            while (j<=m && fabs(c[j][i])<eps) j++;  //从下面方程找一个第i位不为0的 
            if (j==m+1) continue;  //不存在第i位不为0的方程 
            r++;  //矩阵的秩
            for (int k=1;k<=n;k++) swap(c[r][k],c[j][k]);  //存在第i位不为0的方程,交换上去 
            swap(b[r],b[j]);
            
            for (int j=1;j<=m;j++) {  //以r方程回代m个方程 
                if (r==j) continue;
                double rate=c[j][i]/c[r][i];
                for (int k=i;k<=n;k++) c[j][k]-=c[r][k]*rate;
                b[j]-=b[r]*rate;
            }  
        }
        
    //    for (int i=1;i<=m;i++) if (b[i]) {  //判断无解情况 
    //        bool ok=0;
    //        for (int j=1;j<=n;j++) if (c[i][j]) { ok=1; break; }
    //        if (!ok) { puts("Inconsistent data."); return; }
    //    }
        
        //if (r<n) { puts("Multiple solutions."); return; }  //有解但多解
        
        for (int i=1;i<=n;i++) b[i]=b[i]/c[i][i];  //唯一解求解 
    }
    
    int main()
    {
        cin>>n>>k; m=n;
        for (int i=1;i<=k;i++) {
            int x,y; scanf("%d%d",&x,&y);
            G[x].push_back(y);
            G[y].push_back(x);
            e[i].x=x; e[i].y=y; e[i].gx=0;
        }
        memset(c,0,sizeof(c));
        memset(b,0,sizeof(b));
        for (int i=1;i<=n;i++) {
            c[i][i]+=1.0;
            if (i==n) break;
            for (int j=0;j<G[i].size();j++) {
                int v=G[i][j];
                if (v==n) continue;
                c[i][v]-=1.0/G[v].size();
            }
            if (i==1) b[i]+=1.0;
        }
        Gauss();
        for (int i=1;i<=k;i++) {
            e[i].gx+=b[e[i].x]/G[e[i].x].size();
            e[i].gx+=b[e[i].y]/G[e[i].y].size();
        }
        sort(e+1,e+k+1);
        double ans=0;
        for (int i=1;i<=k;i++) ans+=e[i].gx*i;
        printf("%.3lf
    ",ans);
        return 0;
    }
  • 相关阅读:
    linux less-分屏上下翻页浏览文件内容
    linux tail-在屏幕上显示指定文件的末尾若干行
    linux cut-连接文件并打印到标准输出设备上
    linux od-输出文件的八进制、十六进制等格式编码的字节
    linux hexdump-显示文件十六进制格式
    linux whereis-查找二进制程序、代码等相关文件路径
    linux find-在指定目录下查找文件
    linux which-查找并显示给定命令的绝对路径
    linux diff3-比较3个文件不同的地方
    Datetimepicker实现秒钟选择下拉框
  • 原文地址:https://www.cnblogs.com/clno1/p/11628865.html
Copyright © 2011-2022 走看看