zoukankan      html  css  js  c++  java
  • 概率dp-九度-1546-迷宫问题

    题目链接:

    http://ac.jobdu.com/problem.php?pid=1546

    题目意思:

    有一个起点S,多个出口E,#代表不能走,每次等概率的随机选择下一个可以行走的位置,求从S到出口的期望。

    解题思路:

    高斯消元求解期望。

    先BFS预处理能够到达的出口的位置,然后如果从起点不能到达终点,直接输出-1.

    然后对于无效的点,置该未知数的解为-1,否则依据dp[i][j]=1+dp[i-1][j]*1/4+dp[i][j+1]*1/4+dp[i+1][j]*1/4+dp[i][j-1]*1/4,构建n*m个方程,注意有些位置的可行位置数小于4,为cnt的话,此时的下一步概率为1/cnt.

    然后解方程,求出唯一解。

    PS:

    解方程时,如果有的未知数有解,有的无解,可以将无解的情况置一个特殊值,然后按有唯一解的方式来解方程,避免无解未知数对有解未知数的影响。

    方程系数要清零。wa了好几次。

    代码:

    #include<iostream>
    #include<cmath>
    #include<cstdio>
    #include<sstream>
    #include<cstdlib>
    #include<string>
    #include<cstring>
    #include<algorithm>
    #include<vector>
    #include<map>
    #include<set>
    #include<stack>
    #include<list>
    #include<queue>
    #include<ctime>
    #include<bitset>
    #define eps 1e-8
    #define INF 0x3f3f3f3f
    #define PI acos(-1.0)
    #define ll __int64
    #define LL long long
    #define lson l,m,(rt<<1)
    #define rson m+1,r,(rt<<1)|1
    #define M 1000000007
    #pragma comment(linker, "/STACK:1024000000,1024000000")
    using namespace std;
    
    #define Maxn 20
    
    char sa[Maxn][Maxn];
    int n,m,num,dir[4][2]={{-1,0},{0,1},{1,0},{0,-1}};
    double dp[Maxn][Maxn],pp[Maxn][Maxn];
    double g[Maxn*Maxn][Maxn*Maxn],ans[Maxn*Maxn];
    bool vis[Maxn][Maxn];
    
    
    void gaosi(int r,int c)
    {
        for(int i=0,j=0;i<r&&j<c;i++,j++)
        {
            int t=i;
            for(int p=i+1;p<=r;p++)
                if(fabs(g[p][j])>fabs(g[t][j]))
                    t=p;
            if(fabs(g[t][j])<eps) //这是多解的情况
                continue;
            if(t-i) //不相同,则交换
            {
                for(int p=j;p<=c;p++)
                    swap(g[t][p],g[i][p]);
            }
            for(int p=i+1;p<=r;p++)
            {
                double tmp=g[p][j]/g[i][j];
                if(fabs(tmp)<eps)
                    continue;
                g[p][j]=0.0;
                for(int q=j+1;q<=c;q++)
                    g[p][q]-=tmp*g[i][q];
            }
        }
        for(int p=r;p>=0;p--)
        {
            if(fabs(g[p][p])<eps) //无解的情况
                continue;
            ans[p]=g[p][c];
            for(int q=r;q>p;q--)
                ans[p]-=g[p][q]*ans[q];
            ans[p]/=g[p][p];
        }
    }
    bool iscan(int x,int y)
    {
        if(x<0||x>=n||y<0||y>=m)
            return false;
        return true;
    }
    int sx,sy;
    
    bool bfs() //从S出发找到所有可行的位置
    {
        bool flag=false;
        queue<pair<int,int> >myq;
        myq.push(make_pair(sx,sy));
        memset(vis,false,sizeof(vis));
        vis[sx][sy]=true;
    
        while(!myq.empty())
        {
            int x=myq.front().first;
            int y=myq.front().second;
    
            myq.pop();
            for(int i=0;i<4;i++)
            {
                int ans=x+dir[i][0],yy=y+dir[i][1];
                if(!iscan(ans,yy)||vis[ans][yy]||sa[ans][yy]=='#')
                    continue;
                vis[ans][yy]=true;
                myq.push(make_pair(ans,yy));
                if(sa[ans][yy]=='E') //能够到达终点
                    flag=true;
            }
        }
        return flag;
    }
    double dl(double a)
    {
        if(fabs(a)<eps)
            return 0;
        return a;
    }
    
    int main()
    {
        while(~scanf("%d%d",&n,&m))
        {
            int ss;
    
            for(int i=0;i<n;i++)
            {
                scanf("%s",sa[i]);
                for(int j=0;j<m;j++)
                {
                    if(sa[i][j]=='S')
                    {
                        sx=i,sy=j;
                        ss=i*m+j;
                    }
                }
            }
            if(!bfs()) //不能够到达终点
            {
                printf("-1
    ");
                continue;
            }
            num=-1;
            int last=n*m;
    
            memset(g,0,sizeof(g));
            for(int i=0;i<n;i++)
                for(int j=0;j<m;j++)
                {
                    num++;
                    int tmp=i*m+j;
                    if(!vis[i][j]) //无解的位置
                    {
                        g[num][tmp]=1;
                        g[num][last]=-1;
                    }
                    else
                    {
                        if(sa[i][j]=='E') //终点位置
                        {
                            g[num][tmp]=1;
                            g[num][last]=0;
                            continue;
                        }
                        int cnt=0,next[5];
                        for(int k=0;k<4;k++) //求出下一步可行的位置数
                        {
                            int x=i+dir[k][0],y=j+dir[k][1];
                            if(iscan(x,y)&&sa[x][y]!='#'&&vis[x][y])
                            {
                                cnt++;
                                next[cnt]=x*m+y;
                            }
                        }
                        g[num][tmp]=1;
                        g[num][last]=1;
                        for(int k=1;k<=cnt;k++) //构建当前位置的方程
                            g[num][next[k]]=-1.0/(cnt*1.0);
                    }
                }
            gaosi(n*m-1,n*m);
            ans[ss]=dl(ans[ss]);
            if(ans[ss]>0)
                printf("%.2f
    ",ans[ss]);
            else
                printf("-1
    ");
        }
       return 0;
    }
    



  • 相关阅读:
    Date计算人活了多少天
    微信红包平均分法
    math practise
    Array sort
    static memory management
    java数组中的选择排序
    java数组中的冒泡排序
    数组联系2 模拟酒店系统
    数组练习1(模拟栈)
    二维数组
  • 原文地址:https://www.cnblogs.com/suncoolcat/p/3358046.html
Copyright © 2011-2022 走看看