九度oj 题目1546:迷宫问题 (概率dp guess消元)


题目链接:点击打开链接

题目描述:


给定一个n*m的迷宫,如

S..

..#

E.E

其中,S代表开始位置,#代表不可行走的墙,E代表出口。

主人公从开始位置出发,每次等概率的随机选择下一个可以行走的位置,直到到达某一个出口为止。

现在他想知道,在这一概率事件中,它从开始位置走到某一个出口的期望步数是多少。

输入:

输入包含多组测试用例,每组测试用例由两个整数n,m(1<=n,m<=15)开始,代表迷宫的大小

接下去n行每行m个字符描述迷宫信息,具体规则如题面所述。

数据保证至少存在一个E和一个S,但可能存在多个E。

输出:

输出一个浮点数,表示他走出迷宫的期望步数,保留两位小数。若主人公不可能走出迷宫,输出-1。

样例输入:
1 2
SE
2 2
S.
.E
1 3
S#E
样例输出:
1.00
4.00
-1
提示:

走到.之后会有几率往回走。

题意:

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

思路:

先bfs预处理能到达的点,不能到达终点则输出-1,否则dp。

dp[i]-到达i点后要到达终点需要的步数的期望。

对每一个能到达的点x0,假设其相邻的能到达的点有x1、x2、x3.

则dp[x0]=1+dp[x1]/3+dp[x2]/3+dp[x3];

ps:注意可能有多个终点,终点的期望都为0.

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <string>
#include <map>
#include <stack>
#include <vector>
#include <set>
#include <queue>
#pragma comment (linker,"/STACK:102400000,102400000")
#define maxn 405
#define MAXN 100005
#define OO (1LL<<35)-1
#define mod 1000000009
#define INF 0x3f3f3f3f
#define pi acos(-1.0)
#define eps 1e-6
typedef long long ll;
using namespace std;

int n,m,sx,sy,flag,cnt;
double a[maxn][maxn],x[maxn];
//方程的左边的矩阵和等式右边的值,求解之后x存的就是结果  下标从0开始
int equ,var;//方程数和未知数个数
char mp[25][25];
int vis[25][25];
int dx[]= {-1,1,0,0};
int dy[]= {0,0,-1,1};
struct node
{
    int x,y;
} cur,now;

int Gauss()
{
    int i,j,k,col,max_r;
    for(k=0,col=0; k<equ&&col<var; k++,col++)
    {
        max_r=k;
        for(i=k+1; i<equ; i++)
            if(fabs(a[i][col])>fabs(a[max_r][col]))
                max_r=i;
        if(fabs(a[max_r][col])<eps)return 0;
        if(k!=max_r)
        {
            for(j=col; j<var; j++)
                swap(a[k][j],a[max_r][j]);
            swap(x[k],x[max_r]);
        }
        x[k]/=a[k][col];
        for(j=col+1; j<var; j++)a[k][j]/=a[k][col];
        a[k][col]=1;
        for(i=0; i<equ; i++)
            if(i!=k)
            {
                x[i]-=x[k]*a[i][k];
                for(j=col+1; j<var; j++)a[i][j]-=a[k][j]*a[i][col];
                a[i][col]=0;
            }
    }
    return 1;
}
bool isok(int x,int y)
{
    if(x<1||x>n||y<1||y>m) return false ;
    return true ;
}
void bfs()
{
    int i,j,t,tx,ty;
    flag=0;
    memset(vis,-1,sizeof(vis));
    cnt=-1;
    vis[sx][sy]=++cnt;
    queue<node>q;
    cur.x=sx, cur.y=sy;
    q.push(cur);
    while(!q.empty())
    {
        now=q.front();
        if(mp[now.x][now.y]==‘E‘) flag=1;
        q.pop();
        for(i=0; i<4; i++)
        {
            tx=now.x+dx[i];
            ty=now.y+dy[i];
            if(isok(tx,ty)&&mp[tx][ty]!=‘#‘&&vis[tx][ty]==-1)
            {
                cur.x=tx;
                cur.y=ty;
                vis[tx][ty]=++cnt;
                q.push(cur);
            }
        }
    }
}
void solve()
{
    int i,j,k,t,tx,ty,ha,cxx;
    equ=var=cnt+1;
    memset(a,0,sizeof(a));  // 记得初始化
    memset(x,0,sizeof(x));
    for(i=1; i<=n; i++)
    {
        for(j=1; j<=m; j++)
        {
            if(vis[i][j]==-1) continue ;
            ha=vis[i][j];
            if(mp[i][j]==‘E‘)  // 终点的期望为0
            {
                a[ha][ha]=1;
                x[ha]=0;
                continue ;
            }
            cxx=0;
            for(k=0; k<4; k++)
            {
                tx=i+dx[k];
                ty=j+dy[k];
                if(isok(tx,ty)&&vis[tx][ty]!=-1)
                {
                    cxx++;
                    a[ha][vis[tx][ty]]=-1;
                }
            }
            a[ha][ha]=cxx;
            x[ha]=cxx;
        }
    }
    Gauss();
    printf("%.2f\n",x[vis[sx][sy]]);
}
int main()
{
    int i,j,t;
    while(~scanf("%d%d",&n,&m))
    {
        for(i=1; i<=n; i++)
        {
            scanf("%s",mp[i]+1);
            for(j=1; j<=m; j++)
            {
                if(mp[i][j]==‘S‘) sx=i,sy=j;
            }
        }
        bfs();
        if(!flag) printf("-1\n");
        else
        {
            solve();
        }
    }
    return 0;
}
/*
1 2
SE
2 2
S.
.E
1 3
S#E
*/

九度oj 题目1546:迷宫问题 (概率dp guess消元)

时间: 2024-10-08 20:04:22

九度oj 题目1546:迷宫问题 (概率dp guess消元)的相关文章

九度oj 题目1007:奥运排序问题

九度oj 题目1007:奥运排序问题   恢复 题目描述: 按要求,给国家进行排名. 输入:                        有多组数据. 第一行给出国家数N,要求排名的国家数M,国家号从0到N-1. 第二行开始的N行给定国家或地区的奥运金牌数,奖牌数,人口数(百万). 接下来一行给出M个国家号. 输出:                        排序有4种方式: 金牌总数 奖牌总数 金牌人口比例 奖牌人口比例 对每个国家给出最佳排名排名方式 和 最终排名 格式为: 排名:排名

【bzoj1778】[Usaco2010 Hol]Dotp 驱逐猪猡 矩阵乘法+概率dp+高斯消元

题目描述 奶牛们建立了一个随机化的臭气炸弹来驱逐猪猡.猪猡的文明包含1到N (2 <= N <= 300)一共N个猪城.这些城市由M (1 <= M <= 44,850)条由两个不同端点A_j和B_j (1 <= A_j<= N; 1 <= B_j <= N)表示的双向道路连接.保证城市1至少连接一个其它的城市.一开始臭气弹会被放在城市1.每个小时(包括第一个小时),它有P/Q (1 <= P <=1,000,000; 1 <= Q <

LightOJ - 1151概率dp+高斯消元

概率dp+高斯消元 https://vjudge.net/problem/LightOJ-1151 题意:刚开始在1,要走到100,每次走的距离1-6,超过100重来,有一些点可能有传送点,可以传送到前面或后面,那么概率dp没法递推,只能高斯消元 设期望E(x),首先100这个位置的期望E(100)=0,然后可以找出方程, 对于传送点,E(x)=E(go(x)),对于非传送点,E(x)=(E(x+1)+E(x+2)+E(x+3)+E(x+4)+E(x+5)+E(x+6)+6)/cnt(cnt是可

九度oj题目1009:二叉搜索树

题目描述: 判断两序列是否为同一二叉搜索树序列 输入:                        开始一个数n,(1<=n<=20) 表示有n个需要判断,n= 0 的时候输入结束. 接下去一行是一个序列,序列长度小于10,包含(0~9)的数字,没有重复数字,根据这个序列可以构造出一颗二叉搜索树. 接下去的n行有n个序列,每个序列格式跟第一个序列一样,请判断这两个序列是否能组成同一颗二叉搜索树. 输出:                        如果序列相同则输出YES,否则输出NO 样

【BZOJ3640】JC的小苹果 概率DP+高斯消元

[BZOJ3640]JC的小苹果 Description 让我们继续JC和DZY的故事. “你是我的小丫小苹果,怎么爱你都不嫌多!” “点亮我生命的火,火火火火火!” 话说JC历经艰辛来到了城市B,但是由于他的疏忽DZY偷走了他的小苹果!没有小苹果怎么听歌!他发现邪恶的DZY把他的小苹果藏在了一个迷宫里.JC在经历了之前的战斗后他还剩下hp点血.开始JC在1号点,他的小苹果在N号点.DZY在一些点里放了怪兽.当JC每次遇到位置在i的怪兽时他会损失Ai点血.当JC的血小于等于0时他就会被自动弹出迷

【概率DP/高斯消元】BZOJ 2337:[HNOI2011]XOR和路径

2337: [HNOI2011]XOR和路径 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 682  Solved: 384[Submit][Status][Discuss] Description 几乎是一路看题解过来了.. 拖了一个星期的题目- - 已然不会概率DP(说得好像什么时候会过一样),高斯消元(打一次copy一遍). 发现异或题目的新解决方法:按位处理.. 发现DP新方法:高斯消元. f[k][i]代表第k位权值起点为i到终点时答案

【概率dp 高斯消元】bzoj3270: 博物馆

一类成环概率dp的操作模式 Description 有一天Petya和他的朋友Vasya在进行他们众多旅行中的一次旅行,他们决定去参观一座城堡博物馆.这座博物馆有着特别的样式.它包含由m条走廊连接的n间房间,并且满足可以从任何一间房间到任何一间别的房间. 两个人在博物馆里逛了一会儿后两人决定分头行动,去看各自感兴趣的艺术品.他们约定在下午六点到一间房间会合.然而他们忘记了一件重要的事:他们并没有选好在哪儿碰面.等时间到六点,他们开始在博物馆里到处乱跑来找到对方(他们没法给对方打电话因为电话漫游费

【BZOJ4820】[Sdoi2017]硬币游戏 AC自动机+概率DP+高斯消元

[BZOJ4820][Sdoi2017]硬币游戏 Description 周末同学们非常无聊,有人提议,咱们扔硬币玩吧,谁扔的硬币正面次数多谁胜利.大家纷纷觉得这个游戏非常符合同学们的特色,但只是扔硬币实在是太单调了.同学们觉得要加强趣味性,所以要找一个同学扔很多很多次硬币,其他同学记录下正反面情况.用H表示正面朝上,用T表示反面朝上,扔很多次硬币后,会得到一个硬币序列.比如HTT表示第一次正面朝上,后两次反面朝上.但扔到什么时候停止呢?大家提议,选出n个同学,每个同学猜一个长度为m的序列,当某

九度oj 题目1171:C翻转

题目描述: 首先输入一个5 * 5的数组,然后输入一行,这一行有四个数,前两个代表操作类型,后两个数x y代表需操作数据为以x y为左上角的那几个数据. 操作类型有四种:  1 2 表示:90度,顺时针,翻转4个数  1 3 表示:90度,顺时针,翻转9个数  2 2 表示:90度,逆时针,翻转4个数  2 3 表示:90度,逆时针,翻转9个数 输入: 输入有多组数据. 每组输入一个5 * 5的数组,然后输入一行,这一行有四个数,前两个代表操作类型,后两个数x y代表需操作数据为以x y为左上角