Maze Problem BNUOJ 1055

来源:互联网 发布:淘宝助理ios下载 编辑:程序博客网 时间:2024/05/28 01:34

Maze Problem BNUOJ 1055

Time Limit: 1000ms      Memory Limit: 65535KB走迷宫是很有趣的一种游戏,能够锻炼人的记忆力和思维.现在,HK被困在一个迷宫里面了,请你帮助他计算一下有多少种不同的走法,能够让他走出迷宫.这个迷宫很奇怪,HK只能够沿着向上或者向右的方向走,不能回头.迷宫使用一个N*M的矩阵来描述,矩阵中用'.'代表空格可以通行,用'*'代表障碍物,用'S'代表出发点,用'T'代表出口.例如下面的一个矩阵就描述了一个8*8的迷宫.....T....*****.......*.*.***.*.......*..****.*.S..*............Input每个输入文件只包含一组输入数据.每组数据第一行是两个正整数N和M(N,M<=100).接着是一个N*M的矩阵.Output输出HK能够选用的不同方法数(由于结果可能很大,输出模1908的余数即可).8 8.....T....*****.......*.*.***.*.......*..****.*.S..*............Sample Output1问题分析:看到这个题我的第一反应是用dfs,从起点开始,一次检索两个方向上的可能性,如果符合题意,则继续深入递归,直至到达终点,让count++并返回,继续递归。于是我写了一个dfs的程序,本地测试了几组数据,都是正常产出。我把代码交到oj,结果很意外:Time Limit Exceed. 我去?居然是超时。但是仔细想想,就不难发现,这题就是个神坑。为什么dfs会超时?因为在递归调用的时候,我重复计算了太多问题。因为之前某种方法走到某一点后的状态,从这点到终点的方法数会在之后某种方法中途到底此点后再次调用dfs递归计算,这简直就是扯淡。重复计算?想到了什么?对,就是dp!

(注:
动态规划有两种基本结构:
一、带备忘的自顶向下的递归
就是把之前的算过的一些dfs值储存在一个数组里,把重复的递归调用转化为数组数据的直接访问。
二、自底向上的动态规划
就是把问题分成一系列子问题之后,找清楚各个子问题之间的相互依赖关系,即子问题的子问题,子子问题,然后从最小规模的子问题开始计算,自底向上,保证只有当某个问题的所有依赖子问题都计算完成后,才计算这个问题。
这两种算法时间界相近,第二种系数更小些。)

好了,那么改做法,dp做法就不用多说了下面附上代码
/** *name: Maze_2 *p_ID: bnuoj 1055 */#include <cstdio>#include <cstring>#include <cmath>#include <iostream>using namespace std;int N, M, x, y, xx, yy;char str[101][101];bool vis[101][101];int dp[101][101];void dpsearch(int p, int q){    if(p>x || q<y || str[p][q]=='*') return;    if(!vis[p][q])    {        vis[p][q] = true;        dpsearch(p+1, q);        dpsearch(p, q-1);        if(p<N)            dp[p][q] += dp[p+1][q]%1908;        if(q>0)            dp[p][q] += dp[p][q-1]%1908;    }}int main(){    while(scanf("%d%d", &N, &M)!=EOF)    {        memset(str, '\0', sizeof(str));        memset(vis, false, sizeof(vis));        memset(dp, 0, sizeof(dp));        int i=0;        for(int i=0; i<N; i++)            scanf("%s", str[i]);        for(int i=0; i<N; i++)        {            for(int j=0; j<M; j++)            {                if(str[i][j]=='S')                {                    x = i;                    y = j;                }                if(str[i][j]=='T')                {                    xx = i;                    yy = j;                }            }        }        dp[x][y] = 1;        dpsearch(xx, yy);        printf("%d\n", dp[xx][yy]%1908);    }    return 0;}
我把原来的dfs也附上,方便反省。。。
/** *name: Maze_2 *p_ID: bnuoj 1055 */#include <cstdio>#include <cstring>#include <cmath>#include <iostream>using namespace std;int N, M, x, y, num = 0;int dir[][2] = {{-1,0}, {0, 1}};char str[101][101];bool vis[101][101];bool easyGo(int x, int y){    if(x>=0 && y>=0 && x<N && y<M && str[x][y]!='*' && !vis[x][y])        return true;    else return false;}void dfs(int x, int y){    if(str[x][y]=='T')    {        num++;        num %= 1908;        return;    }    if(easyGo(x-1, y))    {        vis[x-1][y] = true;        dfs(x-1, y);        vis[x-1][y] = false;    }    if(easyGo(x, y+1))    {        vis[x][y+1] = true;        dfs(x, y+1);        vis[x][y+1] = false;    }    return;}int main(){    while(scanf("%d%d", &N, &M)!=EOF)    {        num = 0;        memset(str, '\0', sizeof(str));        memset(vis, false, sizeof(vis));        int i=0;        for(int i=0; i<N; i++)            scanf("%s", str[i]);        int flag = 1;        for(int i=0; i<N; i++)        {            for(int j=0; j<M; j++)            {                if(str[i][j]=='S')                {                    x = i;                    y = j;                    vis[i][j] = true;                    flag = 0;                    break;                }            }            if(flag==0)                break;        }        dfs(x, y);        printf("%d\n", num);    }}
0 0