概率dp——蘑菇阵

https://www.nowcoder.com/question/next?pid=573288&qid=25948&tid=31433178

现在有两个好友A和B,住在一片长有蘑菇的由n*m个方格组成的草地,A在(1,1),B在(n,m)。现在A想要拜访B,由于她只想去B的家,所以每次她只会走(i,j+1)或(i+1,j)这样的路线,在草地上有k个蘑菇种在格子里(多个蘑菇可能在同一方格),问:A如果每一步随机选择的话(若她在边界上,则只有一种选择),那么她不碰到蘑菇走到B的家的概率是多少?

输入描述:

第一行N,M,K(1 ≤ N,M ≤ 20, k ≤ 100),N,M为草地大小,接下来K行,每行两个整数x,y,代表(x,y)处有一个蘑菇。

输出描述:

输出一行,代表所求概率(保留到2位小数)

输入例子1:

2 2 1
2 1

输出例子1:

0.50

思路:该题想明白转移是由dp[i-1][j]和dp[i][j-1]得到便可,注意边界限制便很好写,用路径的话走不同路径的概率实际上是不相等的。ps:注意每个点的概率来源,第一行的点,如(1,3)的概率来源只有它左边点(1,2)的1/2,

第n行的点如(n,3),概率来源为(n,2)+(n-1,3)*1/2,因为(n,2)只能往右走,概率为1。其他的特征点在程序段中列出

代码:

#include<bits/stdc++.h>
using namespace std;
int n,m,k,x,y;
int mp[100][100];
double dp[100][100];
int main()
{
    while(scanf("%d%d%d",&n,&m,&k)!=EOF){
        memset(mp,0,sizeof(mp));
        for(int i=1;i<=k;i++){
            scanf("%d%d",&x,&y);
            mp[x][y]=1;
        }
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                if(mp[i][j]==1)
                { dp[i][j]=0;  continue;  }
                if(i==1 && j==1){ dp[1][1]=1;  }
                else if(i==n && j==m){  dp[n][m]=dp[n-1][m]+dp[n][m-1];    }
                else if(i==n){ dp[n][j]=dp[n][j-1]+dp[n-1][j]*0.5   ;  }
                else if(j==m){ dp[i][m]=dp[i-1][m]+dp[i][m-1]*0.5 ;   }
                else if(i==1){ dp[1][j]=dp[1][j-1]*0.5 ;  }
                else if(j==1){ dp[i][j]=dp[i-1][j]*0.5 ; }
                else{
                    dp[i][j]=0.5*dp[i-1][j]+0.5*dp[i][j-1];
                }
        ///        cout<<"i:"<<i<<"  j:"<<j<<"    :"<<dp[i][j]<<endl;
            }
        }
        printf("%.2f\n",dp[n][m]);

    }
}

2.普通概率

钓鱼比赛

链接:https://www.nowcoder.com/questionTerminal/cac8bc877bbd444c8999d7fd77e5dd89
来源:牛客网
 

ss请cc来家里钓鱼,鱼塘可划分为n*m的格子,每个格子有不同的概率钓上鱼,cc一直在坐标(x,y)的格子钓鱼,而ss每分钟随机钓一个格子。问t分钟后他们谁至少钓到一条鱼的概率大?为多少?

输入描述:

第一行五个整数n,m,x,y,t(1≤n,m,t≤1000,1≤x≤n,1≤y≤m);
接下来为一个n*m的矩阵,每行m个一位小数,共n行,第i行第j个数代表坐标为(i,j)的格子钓到鱼的概率为p(0≤p≤1)

输出描述:

输出两行。第一行为概率大的人的名字(cc/ss/equal),第二行为这个概率(保留2位小数)

示例1

输入

2 2 1 1 1
0.2 0.1
0.1 0.4

输出

equal
0.20

这道题坑点就是精度问题。

(灰色注释掉的地方不对是因为每次相除,都会引起精度不对,所以直接加和最后除这样精度强)另外:比较两个double数的大小要用abs(a-b)<1e4

代码:

#include<bits/stdc++.h>
using namespace std;
double mp[1100][1100];
int main()
{
    int x,y,t;
    double n,m;
    double sum;
    while(scanf("%lf%lf%d%d%d",&n,&m,&x,&y,&t)!=EOF){
            sum=0;
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                cin>>mp[i][j];
                sum+=mp[i][j];
            }
        }
        double g1,g2;
        g1=1-pow(1-mp[x][y],t);
       /*for(int i=1;i<=n;i++){
           for(int j=1;j<=m;j++){
               g2=g2+((1-mp[i][j])/(n*m));
           }
       }
       */
       g2=1-pow(1-sum/(n*m),t);
       if(g1>g2){
           printf("cc\n%.2lf\n",g1);
       }
        else if(g1<g2){
            printf("ss\n%.2lf\n",g2);
        }
        else if(abs(g1-g2)<1e4){
            printf("equal\n%.2lf\n",g1);
        }
    }
}
发布了565 篇原创文章 · 获赞 110 · 访问量 11万+

猜你喜欢

转载自blog.csdn.net/xianpingping/article/details/104845547