zoukankan      html  css  js  c++  java
  • 信息传递 计蒜客16863 NOIP模拟赛 概率DP

    题目描述

    输入格式

    输出格式

    数据范围

    样例输入

    3 2
    0 1 0
    0 1 4
    1 0 2
    4 2 0

    样例输出

    0.400000
    0.350000
    0.250000

    题目来源

    2017 NOIP 提高组模拟赛(三)Day1

    本题是一道概率DP,并且很容易模拟出过程。

    先预处理出两两点之间的最短路,本题可以用O(n3)的算法。

    两个点之间的传递概率可以预处理,也可以记忆化处理,这里给一份记忆化计算从i点到j点的概率的代码

    inline double calc(int i,int j)
    {
        if(gl[i][j]!=0) return gl[i][j];
        int res=0;
        for (register int k=1;k<=n;++k) res+=mp[i][k];
        return gl[i][j]=(double)((double)mp[i][j]/(double)res);
    }

     同时我们可以注意到(测试出),当T大到一定值的时候,答案的大小就基本恒定不变了(差异<0.0000001,符合题目要求),也就是说当T的值很大的时候,各点的概率趋近平衡,在1e-6的精度要求下,从数值上看是不变的了。

     那么我们就可以不用在意Tmax=1e9了,我们在读入T之后加上  T=min(T,4000) 即可。当然,这里的4000不是特定的,如果您有更合适的值也可以。4000是可以AC本题的。(我们也可以不限制T,转而维护一个eps:若最近两次更新到某点的概率的差值<1e-7,我们就结束推导过程)

    同时本题直接开数组是开不下的,我们注意到当前状态仅由上一次的推导而来(对应题目中“在传递到下一个节点后,该数据包会自动删除在当前节点的备份。”这句话)。

    所以我们可以加上滚动数组的优化,当前状态由上一状态的所有点的概率乘以传递概率求和而来。最后输出结果即可

    附上AC代码

     1 #include<cstdio>
     2 #include<algorithm>
     3 #include<cstring>
     4 using namespace std;
     5 template<class _T>inline void read(_T &_a)
     6 {
     7     char _ch=getchar();_a=0;
     8     while(_ch<'0'||_ch>'9')_ch=getchar();
     9     while(_ch>='0'&&_ch<='9'){_a=(_a<<3)+(_a<<1)+_ch-'0';_ch=getchar();}
    10 }
    11 
    12 const int maxn=201,maxm=19901;
    13 int n,T,mp[maxn][maxn];
    14 double dp[2][maxn],gl[maxn][maxn];
    15 bool flag;
    16 
    17 inline double calc(int i,int j)
    18 {
    19     if(gl[i][j]!=0) return gl[i][j];
    20     int res=0;
    21     for (register int k=1;k<=n;++k) res+=mp[i][k];
    22     return gl[i][j]=(double)((double)mp[i][j]/(double)res);
    23 }
    24 
    25 int main()
    26 {
    27     freopen("trans.in","r",stdin);
    28     freopen("trans.out","w",stdout);
    29     read(n); read(T);
    30     memset(mp,0x7f,sizeof(mp));
    31     for (register int i=1;i<=n;++i) scanf("%lf",&dp[1][i]);
    32     for (register int i=1;i<=n;++i)
    33      for (register int v=1;v<=n;++v)
    34       read(mp[i][v]),mp[v][i]=mp[i][v];
    35     for (register int k=1;k<=n;++k)
    36      for (register int i=1;i<=n;++i)
    37       for (register int j=1;j<=n;++j)
    38        mp[i][j]=min(mp[i][j],mp[i][k]+mp[k][j]);
    39     T=min(T,4000);
    40     while(T--)
    41     {
    42         bool nxt=flag^1;
    43         for (register int i=1;i<=n;++i)
    44         {
    45             dp[flag][i]=0;
    46             for (register int v=1;v<=n;++v)
    47               if(i!=v) dp[flag][i]+=dp[nxt][v]*calc(v,i);
    48         }
    49         flag=nxt;
    50     }
    51     flag^=1;
    52     for (register int i=1;i<=n;++i) printf("%lf
    ",dp[flag][i]);
    53     return 0;
    54 }
    View Code
  • 相关阅读:
    Reborn
    个人总结
    第十六周个人进度条
    梦断代码阅读笔记03
    第十五周个人进度条
    第十四周个人进度条
    第十三周个人进度条
    冲刺9
    冲刺8
    事后诸葛亮会议
  • 原文地址:https://www.cnblogs.com/jaywang/p/7723546.html
Copyright © 2011-2022 走看看