zoukankan      html  css  js  c++  java
  • 概率dp专场

     

    专题链接

    第一题--poj3744 Scout YYF I  链接 (简单题)

    算是递推题 如果直接推的话 会TLE 会发现 在两个长距离陷阱中间 很长一部分都是重复的 我用 a表示到达i-2步的概率 b表示到达i-1步的概率 c表示到达i步的概率

    如果数很大的话 中间肯定会有重复的a,b,c 直接将i挪到最近的陷阱前一位 i = a[o]-1,大大节省时间。

     1 #include <iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 #include<stdlib.h>
     6 #include<vector>
     7 #include<cmath>
     8 #include<queue>
     9 #include<set>
    10 using namespace std;
    11 #define LL long long
    12 #define INF 0xfffffff
    13 const double eps = 1e-8;
    14 const double pi = acos(-1.0);
    15 const double inf = ~0u>>2;
    16 int x[12];
    17 int main()
    18 {
    19     int i,n,j;
    20     double p;
    21     while(cin>>n)
    22     {
    23         cin>>p;
    24         for(i = 0 ;i < n ;i++)
    25         {
    26             cin>>x[i];
    27         }
    28         sort(x,x+n);
    29         double a = 1.0,b=0.0,c;
    30         double ta = 0,tb = 0;
    31         int o = 0;
    32         if(x[0]==1)
    33         a = 0;
    34         else a = 1;
    35         for(i = 2; i <= x[n-1]+1 ; i++)
    36         {
    37             if(i==x[o])
    38             {
    39                 o++;
    40                 while(x[o]==x[o-1])
    41                 o++;
    42                 c = 0;
    43             }
    44             else
    45             c = a*p+b*(1.0-p);
    46             b = a;
    47             a = c;
    48             if(o<n&&fabs(ta-a)<eps&&fabs(tb-b)<eps)
    49             i = x[o]-1;
    50             ta = a;
    51             tb = b;
    52         }
    53         printf("%.7f
    ",c);
    54     }
    55     return 0;
    56 }
    View Code

    第二题--poj3071Football(简单题)

    dp[i][j] 表示第i场j赢的概率 那么可以写出方程dp[i][j] += dp[i-1][g]*p[j][g]. 

     1 #include <iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 #include<stdlib.h>
     6 #include<vector>
     7 #include<cmath>
     8 #include<queue>
     9 #include<set>
    10 using namespace std;
    11 #define N 100000
    12 #define LL long long
    13 #define INF 0xfffffff
    14 const double eps = 1e-8;
    15 const double pi = acos(-1.0);
    16 const double inf = ~0u>>2;
    17 double p[130][130];
    18 double dp[130][130];
    19 int pp[12];
    20 int main()
    21 {
    22     int i,j,n,g;
    23     pp[0] = 1;
    24     for(i = 1 ;i <= 10 ;i++)
    25     pp[i] = pp[i-1]*2;
    26     while(cin>>n)
    27     {
    28         if(n==-1) break;
    29         memset(dp,0.0,sizeof(dp));
    30         int k = n;
    31         n = pp[n];
    32         for(i = 1; i <=n ; i++)
    33             for(j = 1 ;j <= n; j++)
    34             cin>>p[i][j];
    35         for(i = 1; i <=n ;i++)
    36         {
    37             if(i%2)
    38             dp[1][i] = p[i][i+1];
    39             else
    40             dp[1][i] = p[i][i-1];
    41         }
    42         for(i = 2 ;i <= k ;i++)
    43         {
    44             for(j = 1 ;j <= n ;j+=pp[i])
    45             {
    46                 for(g = j; g < j+pp[i-1] ; g++)
    47                 {
    48                     for(int e = j+pp[i-1] ; e < j+pp[i] ; e++)
    49                     {
    50                         dp[i][g]+=dp[i-1][g]*dp[i-1][e]*p[g][e];
    51                         dp[i][e]+=dp[i-1][e]*dp[i-1][g]*p[e][g];
    52                     }
    53                 }
    54             }
    55         }
    56         double maxz = 0;
    57         int ans;
    58         for(i = 1; i <= n ;i++)
    59         {
    60             if(maxz<dp[k][i])
    61             {
    62                 maxz = dp[k][i];
    63                 ans = i;
    64             }
    65             //printf("%.5lf %d
    ",dp[k][i],i);
    66         }
    67         cout<<ans<<endl;
    68     }
    69     return 0;
    70 }
    View Code

    第三题--CodeForces 148D(简单题)

    刚开始看错了题意,以为一次跳出一个老鼠,按概率直接算,WA后发现dragon画的时候会另有一只跳出来,这样就根据跳出来的是黑还是白分两种情况计算。

    如果当前是dragon轮 也就是(总数-剩余数)%3!=0 时  dp[i][j] = j/(i+j)*((j-1)/(i+j-1)*dp[i][j-2]+i/(i+j-1)*dp[i-1][j-1])

    dp[i][j] 表示还有i只白老鼠及j只黑老鼠时princess赢的概率。 princess轮计算方式类似。

     1 #include <iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 #include<stdlib.h>
     6 #include<vector>
     7 #include<cmath>
     8 #include<queue>
     9 #include<set>
    10 using namespace std;
    11 #define N 1010
    12 #define LL long long
    13 #define INF 0xfffffff
    14 const double eps = 1e-8;
    15 const double pi = acos(-1.0);
    16 const double inf = ~0u>>2;
    17 double dp[N][N];
    18 int main()
    19 {
    20     int i,a,b,j;
    21     while(cin>>a>>b)
    22     {
    23         memset(dp,0,sizeof(dp));
    24         for(i = 1 ;i <= a ; i++)
    25         {
    26             if((a+b-i)%3==0)
    27             dp[i][0] = 1;
    28         }
    29         for(i = 1 ; i <= a ;i++)
    30             for(j = 1 ;j <= b ;j++)
    31             {
    32                 if((a+b-(i+j))%3)
    33                 {
    34                     if(j>=2)
    35                     dp[i][j] = j*1.0/(i+j)*((j-1)*1.0/(i+j-1)*dp[i][j-2]+(i*1.0)/(i+j-1)*dp[i-1][j-1]);
    36                     else
    37                     dp[i][j] = j*1.0/(i+j)*dp[i-1][j-1];
    38                 }
    39                 else
    40                 {
    41                     dp[i][j] = i*1.0/(i+j)+j*1.0/(i+j)*dp[i][j-1];
    42                 }
    43                 //cout<<i<<" "<<j<<" "<<dp[i][j]<<endl;
    44             }
    45         printf("%.9lf
    ",dp[a][b]);
    46     }
    47     return 0;
    48 }
    View Code

     第四题--POJ 2151 Check the difficulty of problems 

    这个题正推不好推,可以求逆,dp[i][j][g]表示第i个队在前g个题里解决了j道题的概率 再令开一dd[i][j]累加和保存第i队最多解决了j道题的概率

    这样依次求出每队解决大于1道题的概率减掉每队解决少于n道的概率 即为每队至少解决一道并且冠军队解决至少n道的概率

     1 #include <iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 #include<stdlib.h>
     6 #include<vector>
     7 #include<cmath>
     8 #include<queue>
     9 #include<set>
    10 using namespace std;
    11 #define N 1010
    12 #define LL long long
    13 #define INF 0xfffffff
    14 const double eps = 1e-12;
    15 const double pi = acos(-1.0);
    16 const double inf = ~0u>>2;
    17 double dp[N][45][45],dd[N][45];
    18 double p[N][45];
    19 int main()
    20 {
    21     int i,j,n,m,t,g,e;
    22     while(cin>>m>>t>>n)
    23     {
    24         if(!n||!m||!t) break;
    25         memset(dp,0.0,sizeof(dp));
    26         memset(dd,0.0,sizeof(dd));
    27         for(i = 1; i <= t ; i++)
    28         {
    29             dp[i][0][0] = 1.0;
    30             for(j = 1; j <= m ;j++)
    31             {
    32                 cin>>p[i][j];
    33                 dp[i][0][j] = (1.0-p[i][j])*dp[i][0][j-1];
    34             }
    35             dd[i][0] = dp[i][j][m];
    36         }
    37         for(i = 1 ;i <= t ;i++)
    38             for(j = 1 ;j <= m ;j++)
    39             {
    40                 e = 1 ;
    41                 for(g = j ;g <= m ; g++)
    42                 {
    43                     dp[i][j][g] = dp[i][j-1][g-1]*p[i][g]+dp[i][j][g-1]*(1-p[i][g]);
    44                 }
    45                 dd[i][j] = dd[i][j-1]+dp[i][j][m];
    46             }
    47         double ans = 1.0,ss=1.0;
    48         for(i = 1; i <= t; i++)
    49         {
    50             ans*=dd[i][m]-dd[i][0];
    51             ss*=dd[i][n-1]-dd[i][0];
    52         }
    53         printf("%.3f
    ",ans-ss);
    54     }
    55     return 0;
    56 }
    View Code

    第五题--POJ 2096 Collecting Bugs (简单期望题)

    学习完这题可以了解到这一类期望题的解法,确定好一个边界状态,可能是初态也可能是终态,然后向后或向前推。

    这题可以确定的为终态,dp[n][s] = 0. 然后倒推就可以了 dp[i][j] = dp[i][j+1]*(s-j)*1.0/s*i/n+dp[i+1][j]*(n-i)/n*j/s+dp[i+1][j+1]*(n-i)/n*(s-j)/s+1+i*j*1.0/n/s;

    一个方程一个未知数,dp[0][0]即为答案。

     1 #include <iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 #include<stdlib.h>
     6 #include<vector>
     7 #include<cmath>
     8 #include<queue>
     9 #include<set>
    10 using namespace std;
    11 #define N 1010
    12 #define LL long long
    13 #define INF 0xfffffff
    14 const double eps = 1e-8;
    15 const double pi = acos(-1.0);
    16 const double inf = ~0u>>2;
    17 double dp[N][N];
    18 int main()
    19 {
    20     int n,s,i,j;
    21     while(cin>>n>>s)
    22     {
    23         memset(dp,0.0,sizeof(dp));
    24         for(i = n ; i >= 0 ;i--)
    25             for(j = s ; j >= 0 ;j--)
    26             {
    27                 if(i==n&&j==s) continue;
    28                 dp[i][j] = dp[i][j+1]*(s-j)*1.0/s*i/n+dp[i+1][j]*(n-i)/n*j/s+
    29                 dp[i+1][j+1]*(n-i)/n*(s-j)/s+1;
    30                 dp[i][j] = dp[i][j]/(1-(i*j*1.0/n/s));
    31 
    32             }
    33         printf("%.4f
    ",dp[0][0]);
    34     }
    35     return 0;
    36 }
    View Code

    第六题--HDU 3853 LOOPS(简单期望题)

    与上一题类似,可以确定终态 dp[r][c] = 0.然后根据可走的概率进行倒推,注意可能会有无解的情况,p[i][j][0]=1就会进入死循环。

     1 #include <iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 #include<stdlib.h>
     6 #include<vector>
     7 #include<cmath>
     8 #include<queue>
     9 #include<set>
    10 using namespace std;
    11 #define N 1010
    12 #define LL long long
    13 #define INF 0xfffffff
    14 const double eps = 1e-8;
    15 const double pi = acos(-1.0);
    16 const double inf = ~0u>>2;
    17 double dp[N][N];
    18 double p[N][N][3];
    19 int main()
    20 {
    21 
    22     int i,j,r,c;
    23     while(cin>>r>>c)
    24     {
    25         memset(dp,0.0,sizeof(dp));
    26         for(i = 1; i <= r ; i++)
    27         {
    28             for(j = 1; j <= c; j++)
    29             {
    30                 for(int g = 0 ; g < 3 ; g++)
    31                 scanf("%lf",&p[i][j][g]);
    32             }
    33         }
    34         for(i = r ; i >= 1 ; i--)
    35         {
    36             for(j = c ; j >= 1 ; j--)
    37             {
    38                 if(i==r&&j==c) continue;
    39                 dp[i][j] = dp[i+1][j]*p[i][j][2]+dp[i][j+1]*p[i][j][1]+2;
    40                 if(fabs(1-p[i][j][0])<eps) continue;
    41                 dp[i][j] = dp[i][j]/(1-p[i][j][0]);
    42             }
    43         }
    44         printf("%.3lf
    ",dp[1][1]);
    45     }
    46     return 0;
    47 }
    View Code

    第七题--HDU 4405 Aeroplane chess (简单期望题)

    投掷骰子的问题,也是一样的问题,确定终态求dp[0]。

     1 #include <iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 #include<stdlib.h>
     6 #include<vector>
     7 #include<cmath>
     8 #include<queue>
     9 #include<set>
    10 using namespace std;
    11 #define N 101000
    12 #define LL long long
    13 #define INF 0xfffffff
    14 const double eps = 1e-8;
    15 const double pi = acos(-1.0);
    16 const double inf = ~0u>>2;
    17 int f[N];
    18 double dp[N];
    19 int main()
    20 {
    21     int n,m,i,j;
    22     while(cin>>n>>m)
    23     {
    24         if(!n&&!m) break;
    25         memset(f,0,sizeof(f));
    26         memset(dp,0,sizeof(dp));
    27         int x,y;
    28         for(i = 1 ;i <=m ; i++ )
    29         {
    30             cin>>x>>y;
    31             f[x] = y;
    32         }
    33         for(i = n-1 ; i >= 0 ; i--)
    34         {
    35             if(f[i])
    36             dp[i] += dp[f[i]];
    37             else
    38             {
    39                 for(j = 1 ;j <= 6; j++)
    40                 dp[i] += dp[i+j]*1.0/6;
    41                 dp[i]+=1;
    42             }
    43         }
    44         printf("%.4f
    ",dp[0]);
    45     }
    46     return 0;
    47 }
    View Code

    第八题--ZOJ 3640 Help Me Escape (简单期望题)

    这个题是d的战斗力值  也就是当战斗力为多少的时候可以确定一个终态 ,很显然当值为maxz+1 的时候 它最大可达2*maxz.

    这样就可以写出递推方程 dp[i] = (dp[i+c[j]]+1)*1/n;(第j出口所需战斗力》=i) dp[i] += day[j] (第j出口所需战斗力<i)

     1 #include <iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 #include<stdlib.h>
     6 #include<vector>
     7 #include<cmath>
     8 #include<queue>
     9 #include<set>
    10 using namespace std;
    11 #define N 20010
    12 #define LL long long
    13 #define INF 0xfffffff
    14 const double eps = 1e-8;
    15 const double pi = acos(-1.0);
    16 const double inf = ~0u>>2;
    17 int c[105];
    18 double dp[N];
    19 int main()
    20 {
    21     int n,f,i,j;
    22     while(cin>>n>>f)
    23     {
    24         memset(dp,0,sizeof(dp));
    25         for(i = 0; i < n ;i++)
    26         cin>>c[i];
    27         sort(c,c+n);
    28         for(i = 2*c[n-1] ; i >= f ; i--)
    29         {
    30             int o = 0,k=0;
    31             double t = 0,tt=0;
    32             for(j = 0 ; j < n ;j++)
    33             {
    34                 if(i>c[j])
    35                 {
    36                     int d = (1.0+sqrt(5.0))/2*c[j]*c[j];
    37                     t+=1.0/n*d;
    38                 }
    39                 else
    40                 {
    41                     k++;
    42                     if(c[j]==0) o++;
    43                     else
    44                     t+=1.0/n*(dp[i+c[j]]+1);
    45                 }
    46             }
    47             if(o&&fabs(1-o*1.0/n)>eps)
    48             dp[i] += (t+1)/(1-o*1.0/n);
    49             dp[i] += t;
    50         }
    51         printf("%.3f
    ",dp[f]);
    52     }
    53     return 0;
    54 }
    View Code

    H第九题--DU 4336 Card Collector(简单期望题)

     状压一下,然后确定终态倒推。

     1 #include <iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 #include<stdlib.h>
     6 #include<vector>
     7 #include<cmath>
     8 #include<queue>
     9 #include<set>
    10 using namespace std;
    11 #define N 20010
    12 #define LL long long
    13 #define INF 0xfffffff
    14 const double eps = 1e-8;
    15 const double pi = acos(-1.0);
    16 const double inf = ~0u>>2;
    17 double dp[1<<20],p[21];
    18 int main()
    19 {
    20     int n,i,j,g;
    21     while(scanf("%d",&n)!=EOF)
    22     {
    23         memset(dp,0,sizeof(dp));
    24         for(i = 0 ;i < n; i++)
    25         scanf("%lf",&p[i]);
    26         for(j = (1<<n)-1 ; j>=0 ; j--)
    27         {
    28             double t = 0;
    29             double o = 0;
    30             for(g = 0; g < n ;g++)
    31             if((1<<g)&j) continue;
    32             else
    33             {
    34                 o+=p[g];
    35                 t+=p[g]*dp[j+(1<<g)];
    36             }
    37             if(fabs(o)>eps)
    38             dp[j] = (t+1)/o;
    39         }
    40         printf("%f
    ",dp[0]);
    41     }
    42     return 0;
    43 }
    View Code

    第十题--SGU 495 Kids and Prizes(简单期望题)

    正推题,这个题比较巧妙,可以确定初始态dp[1] = 1,因为第一个人拿到球的概率就为1,那么第i个拿到球的期望就为,他拿到球的概率*(dp[i-1]+1),他拿到球的概率就等于有球的房间/总房间

    那么有球的房间就为n-dp[i-1],因为期望就为球数,所以dp[i-1]就为拿走的球数。

     1 #include <iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 #include<stdlib.h>
     6 #include<vector>
     7 #include<cmath>
     8 #include<queue>
     9 #include<set>
    10 using namespace std;
    11 #define N 100010
    12 #define LL long long
    13 #define INF 0xfffffff
    14 const double eps = 1e-8;
    15 const double pi = acos(-1.0);
    16 const double inf = ~0u>>2;
    17 double dp[N];
    18 int main()
    19 {
    20     int i,n,m;
    21     while(cin>>n>>m)
    22     {
    23         memset(dp,0,sizeof(dp));
    24         dp[1] = 1;
    25         for(i = 2; i <= m ;i++)
    26         dp[i] = (dp[i-1]+1)*(1-dp[i-1]/n)+dp[i-1]*dp[i-1]/n;
    27         printf("%.10f
    ",dp[m]);
    28     }
    29     return 0;
    30 }
    View Code

    第十一题--ZOJ 3329 One Person Game(简单期望题)

    也是比较好推的题目,相对前面来说会多一个未知数,但是推到最后就会发现只有一个未知数,一个方程一个未知数,可以求解。

    可以把每一步的期望分为2部分保存,可以准确算出的用dp[i]表示 依旧是未知的用o[i]保存他的系数,留到最后求解。

     1 #include <iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 #include<stdlib.h>
     6 #include<vector>
     7 #include<cmath>
     8 #include<queue>
     9 #include<set>
    10 using namespace std;
    11 #define N 1010
    12 #define LL long long
    13 #define INF 0xfffffff
    14 const double eps = 1e-8;
    15 const double pi = acos(-1.0);
    16 const double inf = ~0u>>2;
    17 double dp[N],p[N],o[N];
    18 int main()
    19 {
    20     int i,j,n,k1,k2,k3,g,a,b,c,t;
    21     cin>>t;
    22     while(t--)
    23     {
    24         memset(dp,0,sizeof(dp));
    25         memset(p,0,sizeof(p));
    26         memset(o,0,sizeof(o));
    27         cin>>n>>k1>>k2>>k3>>a>>b>>c;
    28         int k = k1+k2+k3;
    29         for(i = 1; i <= k1 ; i++)
    30             for(j = 1;j <= k2 ; j++)
    31                 for(g = 1; g <= k3 ; g++)
    32                 {
    33                     if(i==a&&j==b&&g==c) continue;
    34                     p[i+j+g]+=1.0/(k1*k2*k3);
    35                 }
    36         for(i = n ; i >= 0 ; i--)
    37         {
    38             for(j = 3; j <= k ; j++)
    39             {
    40                 dp[i]+=dp[i+j]*p[j];
    41                 o[i]+=p[j]*o[i+j];
    42             }
    43             dp[i]+=1;
    44             o[i]+=1.0/(k1*k2*k3);
    45         }
    46         if(fabs(1-o[0])>eps)
    47         dp[0] = dp[0]/(1-o[0]);
    48         printf("%.14f
    ",dp[0]);
    49     }
    50     return 0;
    51 }
    View Code

    第十二题--HDU 4652 Dice

    有两种询问,一种一个推法,n个相同的话,dp[i]表示最后有连续i个相同的到最后有n个相同的点数的期望,dp[i] = 0,dp[i] = 1.0/m*dp[i+1]+1+(m-1)/m*dp[1];

    另开一数组保存dp[1] 的系数,最后求解。

    n个两辆不同,与之类似 dp[i] = ((m-i)*1.0/m*dp[i+1]+1)+1.0/m*dp[1]+1.0/m*dp[2]+....+1.0/m*dp[i]; 化简一下,每次可以消掉一个未知数,求到dp[1]的时候自然只剩了一个未知数。

     1 #include <iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 #include<stdlib.h>
     6 #include<vector>
     7 #include<cmath>
     8 #include<queue>
     9 #include<set>
    10 using namespace std;
    11 #define N 1000010
    12 #define LL long long
    13 #define INF 0xfffffff
    14 const double eps = 1e-8;
    15 const double pi = acos(-1.0);
    16 const double inf = ~0u>>2;
    17 double dp[N],o[N];
    18 int main()
    19 {
    20     int i,t,n,m,k;
    21     while(cin>>t)
    22     {
    23         while(t--)
    24         {
    25             memset(dp,0,sizeof(dp));
    26             memset(o,0,sizeof(o));
    27             scanf("%d%d%d",&k,&m,&n);
    28             if(k==0)
    29             {
    30                 for(i = n-1 ; i >= 1 ; i--)
    31                 {
    32                     dp[i] = 1.0/m*dp[i+1]+1;
    33                     o[i] = 1.0/m*o[i+1]+(m-1)*1.0/m;
    34                 }
    35                 dp[1] = dp[1]/(1-o[1]);
    36                 dp[0] = dp[1]+1;
    37                 printf("%.12f
    ",dp[0]);
    38             }
    39             else
    40             {
    41                 for(i = n-1 ;i >= 1 ; i--)
    42                 {
    43                     dp[i] = ((m-i)*1.0/m*dp[i+1]+1)/(1-(m-i)*1.0/m*o[i+1]-1.0/m);
    44                     o[i] = ((m-i)*1.0/m*o[i+1]+1.0/m)/(1-(m-i)*1.0/m*o[i+1]-1.0/m);
    45                 }
    46                 dp[0] = dp[1]+1;
    47                 printf("%.12f
    ",dp[0]);
    48             }
    49         }
    50     }
    51     return 0;
    52 }
    View Code

    第十三题--HDU 4035 Maze(中等期望题)

    树上求期望的题,其实也与之类似,仔细想下会发现叶子节点的期望状态比较好确定,因为它只有一个父亲节点所以这样写出来的方程会只有2个未知数,一个是父亲节点一个是1号节点,到最后父亲节点肯定只有1,所以又会变成一个方程一个未知数。

    dp[i]表示第i节点到满足结果的期望。

    i为叶子节点 dp[i] = p1i*dp[1]+p2i*dp[fa[i]]+p3i*exit(exit==0)

    这样可以多开两个数组存两个未知数的系数。

    i为非叶子节点 dp[i] = p1i*dp[1]+p2i*1/k*dp[v](v与i相连的节点,共有K个)+p3i*exit。

     1 #include <iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 #include<stdlib.h>
     6 #include<vector>
     7 #include<cmath>
     8 #include<queue>
     9 #include<set>
    10 #include<vector>
    11 using namespace std;
    12 #define N 100010
    13 #define LL long long
    14 #define INF 0xfffffff
    15 const double eps = 1e-10;
    16 const double pi = acos(-1.0);
    17 const double inf = ~0u>>2;
    18 vector<int>ed[N];
    19 double dp[N],p[N][3];
    20 double o[N][2];
    21 int flag;
    22 void dfs(int u,int pre)
    23 {
    24     if(!flag) return ;
    25     int i;
    26     dp[u] = p[u][2];
    27     o[u][0] = p[u][2];
    28     o[u][1] = p[u][0];
    29     int k = ed[u].size();
    30     double pp = 0;
    31     for(i = 0; i < k ; i++)
    32     {
    33         int v = ed[u][i];
    34         if(v==pre) continue;
    35         dfs(v,u);
    36         dp[u]+=p[u][2]/k*dp[v];
    37         o[u][1]+=p[u][2]/k*o[v][1];
    38         pp+=p[u][2]/k*o[v][0];
    39     }
    40     if(u==1)
    41     {
    42         if(fabs(1-(o[u][1]+pp))>eps)
    43         dp[u] = dp[u]/(1-(o[u][1]+pp));
    44         else
    45         flag = 0;
    46         return;
    47     }
    48     if(fabs(1-pp)>eps)
    49     {
    50         dp[u] = (dp[u])/(1-pp);
    51         o[u][1] = (o[u][1])/(1-pp);
    52         o[u][0] = p[u][2]/k/(1-pp);
    53     }
    54     else
    55     {
    56         flag = 0;
    57         return ;
    58     }
    59 }
    60 int main()
    61 {
    62     int i,j,t,n;
    63     int kk = 0;
    64     cin>>t;
    65     while(t--)
    66     {
    67         memset(dp,0,sizeof(dp));
    68         memset(o,0,sizeof(o));
    69         scanf("%d",&n);
    70         flag = 1;
    71         for(i = 1 ;i <= n ;i++)
    72         ed[i].clear();
    73         for(i = 1; i < n ;i++)
    74         {
    75             int u,v;
    76             scanf("%d%d",&u,&v);
    77             ed[u].push_back(v);
    78             ed[v].push_back(u);
    79         }
    80         for(i = 1; i <=n ;i++)
    81         {
    82             int x,y;
    83             scanf("%d%d",&x,&y);
    84             p[i][0] = x/100.0;
    85             p[i][1] = y/100.0;
    86             p[i][2] = 1-p[i][1]-p[i][0];
    87         }
    88         dfs(1,-1);
    89         printf("Case %d: ",++kk);
    90         if(flag)
    91         printf("%f
    ",dp[1]);
    92         else
    93         puts("impossible");
    94     }
    95     return 0;
    View Code

    第十四题--HDU 4418 Time travel(高斯消元求期望)

    这个题意吧有点难理解。。是这个时光机每次可以走1-m步 概率分别为p[i]。

    为了好做,可以加n-2个点统一方向, 0 1 2 3 2 1

    这样dp[i] = (dp[i+1]+1)*p[i+1]+(dp[i+2]+2)*p[i+2]+...(dp[i+m]+m)*p[i+m];

    这样会发现无论你倒推还是正推都无法减少未知数,不过可以列出来n-2个方程,n-2个未知数,高斯消元。

    需要先bfs出是否能够达到,然后保留能够达到的点。

      1 #include <iostream>
      2 #include<cstdio>
      3 #include<cstring>
      4 #include<algorithm>
      5 #include<stdlib.h>
      6 #include<vector>
      7 #include<cmath>
      8 #include<queue>
      9 #include<set>
     10 using namespace std;
     11 #define N 205
     12 #define LL long long
     13 #define INF 0xfffffff
     14 const double eps = 1e-8;
     15 const double pi = acos(-1.0);
     16 const double inf = ~0u>>2;
     17 double p[N],a[N][N],ans[N];
     18 int n,m,y,x,d,dis[N],g;
     19 int zn;
     20 bool vis[N];
     21 void gauss(int zw,int zr)
     22 {
     23     int i,j,k,g = 0;
     24     for(k = 0 ; k < zw && g < zr; k++,g++)
     25     {
     26         i = k;
     27         for(j = k+1 ; j <= zw ; j++)
     28         {
     29             if(fabs(a[j][g])>fabs(a[i][g]))
     30             i = j;
     31         }
     32         if(fabs(a[i][g])<eps)
     33         {
     34             continue;
     35         }
     36         if(i!=k)
     37         for(j = k ;j <= zr ; j++)
     38         swap(a[i][j],a[k][j]);
     39         for(i = k+1 ; i <= zw ; i++)
     40         {
     41             if(fabs(a[i][k])<eps) continue;
     42             double s = a[i][g]/a[k][g];
     43             a[i][g] = 0.0;
     44             for(j = g+1 ; j <= zr; j++)
     45                 a[i][j] -= s*a[k][j];
     46         }
     47     }
     48     for(i = zw ; i >= 0 ; i--)
     49     {
     50         if(fabs(a[i][i])<eps) continue;
     51         double s = a[i][zn];
     52         for(j = i+1 ; j <= zw ;j++)
     53         s-=a[i][j]*ans[j];
     54         ans[i] = s/a[i][i];
     55     }
     56 }
     57 int bfs()
     58 {
     59     int i;
     60     queue<int>q;
     61     memset(vis,0,sizeof(vis));
     62     q.push(x);
     63     vis[x] = 1;
     64     int ff = 0;
     65     while(!q.empty())
     66     {
     67         int u = q.front();
     68         q.pop();
     69         if(u==y||zn-u==y)
     70         {
     71             ff = 1;
     72             continue;
     73         }
     74         for(i = 1; i <= g; i++)
     75         {
     76             int v = (u+dis[i])%zn;
     77             if(!vis[v])
     78             {
     79                 vis[v] = 1;
     80                 q.push(v);
     81             }
     82         }
     83     }
     84     return ff;
     85 }
     86 int main()
     87 {
     88     int t,i,j;
     89     cin>>t;
     90     while(t--)
     91     {
     92         memset(a,0,sizeof(a));
     93         memset(ans,0,sizeof(ans));
     94         scanf("%d%d%d%d%d",&n,&m,&y,&x,&d);
     95         zn = 2*n-2;
     96         g = 0;
     97         double sum = 0;
     98         for(i= 1; i <= m; i++)
     99         {
    100             int  pp;
    101             scanf("%d",&pp);
    102             if(pp>0)
    103             {
    104                 p[++g] = pp/100.0;
    105                 dis[g] = i;
    106                 sum+=p[g]*i;
    107             }
    108         }
    109         if(d>0)
    110         x = zn-x;
    111         if(x==y)
    112         {
    113             puts("0.00");
    114             continue;
    115         }
    116         if(!bfs())
    117         {
    118             puts("Impossible !");
    119             continue;
    120         }
    121         for(i = 0 ; i < zn ; i++)
    122         {
    123             if(!vis[i]) continue;
    124             a[i][i] = 1;
    125             if(i==y||y==zn-i) continue;
    126             for(j = 1 ; j <= g ;j++)
    127             {
    128                 int dd = (dis[j]+i)%zn;
    129                 a[i][dd]-=p[j];
    130             }
    131             a[i][zn] += sum;
    132         }
    133         gauss(zn-1,zn);
    134         printf("%.2f
    ",ans[x]);
    135     }
    136     return 0;
    137 }
    View Code

    第十五题--HDU 4089 Activation(中等概率题)

    这个题因为会出现循环求所以有求期望的感觉。

    分情况看一下 dp[i][j]表示队里有i个人 他在第j的位置到最终结果的概率。

    j==1 dp[i][1] = p1*dp[i][1]+p2*dp[i][i]+p4.

    k>=j>1 dp[i][j] = p1*dp[i][j]+p2*dp[i][j-1]+p3*dp[i-1][j-1]+p4;

    j>k  dp[i][j] = p1*dp[i][j]+p2*dp[i][j-1]+p3*dp[i-1][j-1];

    因为一个i循环里面只有一个dp[i][i]事未知的,可以开一个一维数组保存dp[i][j]里面还有dp[i][i]的系数。

     1 #include <iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 #include<stdlib.h>
     6 #include<vector>
     7 #include<cmath>
     8 #include<queue>
     9 #include<set>
    10 using namespace std;
    11 #define N 2010
    12 #define LL long long
    13 #define INF 0xfffffff
    14 const double eps = 1e-8;
    15 const double pi = acos(-1.0);
    16 const double inf = ~0u>>2;
    17 double dp[N][N],o[N];
    18 int main()
    19 {
    20     int i,j,n,m,k;
    21     double p1,p2,p3,p4;
    22     while(cin>>n>>m>>k)
    23     {
    24         scanf("%lf%lf%lf%lf",&p1,&p2,&p3,&p4);
    25         memset(dp,0,sizeof(dp));
    26         memset(o,0,sizeof(o));
    27         int flag = 1;
    28         if(fabs(1-p2-p1)<eps)
    29         flag = 0;
    30         else
    31         dp[1][1] = p4/(1-p2-p1);
    32         for(i = 2 ;i <= n ;i++)
    33         {
    34             o[0] = 0;
    35             for(j = 1 ; j <= i; j++)
    36             {
    37                 if(j<=k)
    38                 {
    39                     if(j==1)
    40                     {
    41                         dp[i][j]+=p4;
    42                         o[j] = p2;
    43                     }
    44                     else
    45                     {
    46                         dp[i][j] += p4+p2*dp[i][j-1]+p3*dp[i-1][j-1];
    47                         o[j] = p2*o[j-1];
    48                     }
    49                 }
    50                 else
    51                 {
    52                    dp[i][j]+= p2*dp[i][j-1]+p3*dp[i-1][j-1];
    53                    o[j] = p2*o[j-1];
    54                 }
    55                 if(j==i)
    56                 {
    57                     if(fabs(1-p1-o[j])<eps)
    58                     {
    59                         flag = 0;
    60                         break;
    61                     }
    62                     dp[i][j] = dp[i][j]/(1-p1-o[j]);
    63                 }
    64                 else
    65                 {
    66                     if(fabs(1-p1-o[j])<eps)
    67                     {
    68                         flag = 0;
    69                         break;
    70                     }
    71                     dp[i][j] = dp[i][j]/(1-p1);
    72                     o[j] = o[j]/(1-p1);
    73                 }
    74             }
    75             if(!flag) break;
    76             for(j = 1;j < i ;j++)
    77             dp[i][j]+=dp[i][i]*o[j];
    78         }
    79         if(flag)
    80         printf("%.5f
    ",dp[n][m]);
    81         else
    82         printf("%.5f
    ",0.0);
    83     }
    84     return 0;
    85 }
    View Code

    第十六题--ZOJ 3380 Patchouli's Spell Cards(中等题)

    这题没有推出来。。。 组合题,

    dp[i,j]  表示用前i个数字在m个里放了j个位置,这些数字不一定都有用到
       dp[i,j] = ∑ dp[i-1,j-k]*C[m-(j-k),k]          0≤k≤j , k<l
       最后答案为dp[n,m]

    个人认为做法很棒。。

    题解参照

     1 import java.text.*;
     2 import java.io.*;
     3 import java.util.*;
     4 import java.math.*;
     5 import java.applet.*;
     6 public class Main 
     7 {
     8     public static void main(String[] args)
     9     {
    10         Scanner  cin = new Scanner(System.in);
    11         BigInteger [][]dp = new BigInteger[105][105];
    12         BigInteger o = BigInteger.valueOf(0);
    13         BigInteger [][]c = new BigInteger[105][105];
    14         int n,m,i,j,l,k;
    15         for(i=0;i<101;i++)c[i][0]=c[i][i]=BigInteger.valueOf(1);
    16             for(i=2;i<101;i++){
    17                     for(j=1;j<i;j++)
    18                         c[i][j]=c[i-1][j-1].add(c[i-1][j]);
    19                 }
    20         while(cin.hasNext())
    21         {
    22             m = cin.nextInt();
    23             n = cin.nextInt();
    24             l = cin.nextInt();
    25             BigInteger s1 ,s2 = BigInteger.valueOf(0);
    26             s1 = BigInteger.valueOf(n);
    27             s1 = s1.pow(m);
    28             if(l>m)
    29             {
    30                 System.out.println("mukyu~");
    31                 continue;
    32             }
    33             else if(l>m/2)
    34             {
    35                 for(i=l;i<=m;i++)
    36                 {
    37                     s2=s2.add(c[m][i].multiply( BigInteger.valueOf(n-1).pow(m-i) ));
    38                 }
    39                 s2=s2.multiply(BigInteger.valueOf(n));
    40             }
    41             else
    42             {
    43                 for(i = 0; i <= n ;i++)
    44                     for(j = 0; j <= m; j++)
    45                             dp[i][j] = o;
    46                 dp[0][0] = BigInteger.ONE;
    47                 for(i = 1; i <= n ;i++)
    48                 {
    49                     for(j = 0; j <= m ;j++)
    50                     {
    51                         for(k = 0; k <= Math.min(j, l-1) ;k++)
    52                         dp[i][j] = dp[i][j].add(dp[i-1][j-k].multiply(c[m-(j-k)][k]));
    53                     }
    54                 }
    55                 
    56                 s2 = dp[n][m];
    57                 s2 = s1.subtract(s2);
    58             }
    59             BigInteger gc = s2.gcd(s1);
    60             System.out.println(s2.divide(gc)+"/"+s1.divide(gc));
    61         }
    62     }
    63 }
    View Code
  • 相关阅读:
    [Qt] 事件机制(四)
    shell专题(六):条件判断
    最小生成树
    373. Find K Pairs with Smallest Sums
    gradle代理设置
    266. Palindrome Permutation
    53. Maximum Subarray
    378. Kth Smallest Element in a Sorted Matrix
    240. Search a 2D Matrix II
    74. Search a 2D Matrix
  • 原文地址:https://www.cnblogs.com/shangyu/p/3644545.html
Copyright © 2011-2022 走看看