挑战ACM迷宫

来源:互联网 发布:溪山战役知乎 编辑:程序博客网 时间:2024/05/16 11:39

如下图所示的是一个由程序设计题目组成的ACM迷宫。迷宫的左上角是入口,右下角是出口。迷宫中每一个格子都有一个程序设计题目,挑战者要AC该题目后才能通过,大于0的数字表示AC该题目所需的最短时间。数字如果是0表示是陷阱,进去了就出不来。现在的问题是:求挑战者从入口到出口所需的最短时间。

输入

有多组测试实例。

对于每组测试实例,先输入一个数字n(1<n<=100),然后输入n*n个数字表示迷宫中的数字。

输出

对应输出挑战者从入口到出口所需的最短时间。

样例输入

101 0 2 1 2 3 4 2 2 52 1 0 1 3 2 5 7 2 11 1 1 0 1 1 1 3 2 31 2 1 1 0 1 1 1 2 31 1 2 0 2 0 2 3 2 32 2 2 2 3 2 0 2 3 23 2 2 2 1 1 1 0 1 10 1 1 3 0 1 1 2 3 22 0 1 1 2 2 2 2 2 23 2 3 2 3 2 3 2 3 251 2 1 2 51 3 2 4 52 1 0 2 52 1 1 2 12 4 1 1 2

样例输出

min=29min=11
啊啊啊啊啊  这道题目我用了两个小时才撸出来 思路其实挺简单的 但是调试的时候花费了好多时间 这道题目首先
可以分析出来使用BFS来解决 然后题目要求N为100左右所以要使用双向BFS 不然我怕又超时,一共使用三个数组三个
队列,每一队列中的元素可以从上下左右四个方向进行扩展 这里要判断是不是在棋盘内部 用两个数组分别记录从初始
点到改点目前的最短路径,如果扩展的方向刚好Q[x][y]=0则跳过 如果该点没有走过的话 那就直接走 如果该点是走
过的话 那么就要进行第二次的判断 W[X1][Y1]与Q[X1][Y1]+W[X][Y]大小关系 如果是大于就让
W[X1][Y1]=Q[X1][Y1]+W[X][Y] 在调用函数cheak 这个函数的目的是把二维数组里面的值弄为最优解 这里注意边界
以及思路问题 很有可能进入死循环(本人也是在这里耗费了大量时间)
当另外一个数组对应的位置不为0时候 比较sum与[h.x][h.y]+W[h.x][h.y]-Q[h.x][h.y] 这里一定要有减去Q二维
数组的值 这个可以分析出来 循环一层后得出的最小值就是结果了  代码有点长 大家有建议的地方可以在下方评论
#include <iostream>#include <algorithm>#include <queue>#include <stdio.h>#include <cstring>using namespace std;int Q[105][105]= {0};int W[105][105]= {0};int E[105][105]= {0};int L[8]= {1,0,-1,0,0,1,0,-1};int k,n,sum;typedef struct chess{    int x,y,bu;} chess;queue<chess>A;queue<chess>B;queue<chess>C;int in(int x,int y){    if(x>0&&x<=n&&y>0&&y<=n) return 1;    else return 0;}void cheack(chess g,int o){    chess f,h;    C.push(g);    while(!C.empty())    {        h=C.front();C.pop();        for(int i=0; i<4; i++)        {            if(in(h.x+L[2*i],h.y+L[2*i+1])&&Q[h.x+L[2*i]][h.y+L[2*i+1]]!=0)            {                if(o==1)                {                    if(W[h.x+L[2*i]][h.y+L[2*i+1]]==0) continue;                    if(W[h.x+L[2*i]][h.y+L[2*i+1]]>Q[h.x+L[2*i]][h.y+L[2*i+1]]+W[h.x][h.y])                    {                        W[h.x+L[2*i]][h.y+L[2*i+1]]=Q[h.x+L[2*i]][h.y+L[2*i+1]]+W[h.x][h.y];                        f.x=h.x+L[2*i];                        f.y=h.y+L[2*i+1];                        f.bu=h.bu+1;                        C.push(f);                    }                }                else                {                    if(E[h.x+L[2*i]][h.y+L[2*i+1]]==0) continue;                    if(E[h.x+L[2*i]][h.y+L[2*i+1]]>Q[h.x+L[2*i]][h.y+L[2*i+1]]+E[h.x][h.y])                    {                        E[h.x+L[2*i]][h.y+L[2*i+1]]=Q[h.x+L[2*i]][h.y+L[2*i+1]]+E[h.x][h.y];                        f.x=h.x+L[2*i];                        f.y=h.y+L[2*i+1];                        f.bu=h.bu+1;                        C.push(f);                    }                }            }        }    }}void BFS(chess g){    A.push(g);    g.x=n;    g.y=n;    B.push(g);    chess f,h;    W[1][1]=Q[1][1];    E[n][n]=Q[n][n];    sum=999999;    while(1)    {        while(1)        {            h=A.front();            if(h.bu!=k) break;            A.pop();            if(E[h.x][h.y])            {               if(sum>E[h.x][h.y]+W[h.x][h.y]-Q[h.x][h.y])                    sum=E[h.x][h.y]+W[h.x][h.y]-Q[h.x][h.y];            }            for(int i=0; i<4; i++)            {                if(in(h.x+L[2*i],h.y+L[2*i+1])&&Q[h.x+L[2*i]][h.y+L[2*i+1]]!=0)                {                    if(W[h.x+L[2*i]][h.y+L[2*i+1]]==0)                    {                        W[h.x+L[2*i]][h.y+L[2*i+1]]=Q[h.x+L[2*i]][h.y+L[2*i+1]]+W[h.x][h.y];                        f.x=h.x+L[2*i];                        f.y=h.y+L[2*i+1];                        f.bu=h.bu+1;                        A.push(f);                    }                    else if(W[h.x+L[2*i]][h.y+L[2*i+1]]>Q[h.x+L[2*i]][h.y+L[2*i+1]]+W[h.x][h.y])                    {                        W[h.x+L[2*i]][h.y+L[2*i+1]]=Q[h.x+L[2*i]][h.y+L[2*i+1]]+W[h.x][h.y];                        f.x=h.x+L[2*i];                        f.y=h.y+L[2*i+1];                        f.bu=h.bu+1;                        cheack(f,1);                    }                    else continue;                }            }        }        while(1)        {            h=B.front();            if(h.bu!=k) break;            B.pop();            if(W[h.x][h.y])            {                if(sum>E[h.x][h.y]+W[h.x][h.y]-Q[h.x][h.y])                    sum=E[h.x][h.y]+W[h.x][h.y]-Q[h.x][h.y];            }            for(int i=0; i<4; i++)            {                if(in(h.x+L[2*i],h.y+L[2*i+1])&&Q[h.x+L[2*i]][h.y+L[2*i+1]]!=0)                {                    if(E[h.x+L[2*i]][h.y+L[2*i+1]]==0)                    {                        E[h.x+L[2*i]][h.y+L[2*i+1]]=Q[h.x+L[2*i]][h.y+L[2*i+1]]+E[h.x][h.y];                        f.x=h.x+L[2*i];                        f.y=h.y+L[2*i+1];                        f.bu=h.bu+1;                        B.push(f);                    }                    else if(E[h.x+L[2*i]][h.y+L[2*i+1]]>Q[h.x+L[2*i]][h.y+L[2*i+1]]+E[h.x][h.y])                    {                        E[h.x+L[2*i]][h.y+L[2*i+1]]=Q[h.x+L[2*i]][h.y+L[2*i+1]]+E[h.x][h.y];                        f.x=h.x+L[2*i];                        f.y=h.y+L[2*i+1];                        f.bu=h.bu+1;                        cheack(f,2);                    }                    else continue;                }            }        }        if(sum!=999999)        {            printf("min=%d\n",sum);            return;        }        k++;    }}int main(){    while(scanf("%d",&n)!=EOF&&n!=1&&n!=0)    {        chess g;        g.x=1;        g.y=1;        g.bu=0;        while(!A.empty()) A.pop();        while(!B.empty()) B.pop();        while(!C.empty()) C.pop();        memset(Q,0,sizeof(Q));        memset(W,0,sizeof(W));        memset(E,0,sizeof(E));        for(int i=1; i<=n; i++)            for(int j=1; j<=n; j++)                scanf("%d",&Q[i][j]);        k=0;        BFS(g);    }    return 0;}

还有新的方法就是更改步数
#include<cstdio>#include<cstring>#include<iostream>#include<cstdlib>#include<algorithm>#include<queue>using namespace std;int M[111][111];int jude[111][111];int dxy[4][2]= {{1,0},{0,1},{-1,0},{0,-1}};int n;int a,b,c;queue<int> q;int i,j;int bfs(){    a=b=c=0;    q.push(a);    q.push(b);    q.push(c);    jude[a][b]=1;    while(!q.empty())    {        a=q.front();        q.pop();        b=q.front();        q.pop();        c=q.front();        q.pop();        if(a==n-1&&b==n-1)        {            return c+M[a][b];        }        if(M[a][b]>1)        {            q.push(a);            q.push(b);            q.push(c+1);            M[a][b]--;            continue;        }        printf("%d %d %d %d\n",a ,b,c,M[a][b]);        for(i=0; i<4; i++)        {            int aa=a+dxy[i][0];            int bb=b+dxy[i][1];            if(aa>=0&&aa<n&&bb>=0&&bb<n&&!jude[aa][bb]&&M[aa][bb]!=0)            {                jude[aa][bb]=1;                q.push(aa);                q.push(bb);                q.push(c+1);            }        }    }    return -1;}int main(){    while(scanf("%d",&n)!=EOF)    {        for(i=0; i<n; i++)        {            for(j=0; j<n; j++)            {                jude[i][j]=0;                scanf("%d",&M[i][j]);            }        }        int ans=bfs();        if(ans>=0)            printf("min=%d\n",ans);        while(!q.empty())            q.pop();    }    return 0;}这道题目就是把块以及广度搜索结合 每一个位置都是由于三个元素组成的 第一第二个分别是横纵坐标 第三个就是步数 当M对应坐标唯一的时候就是从开始到该点的最短
时间 如果不是一的时候就用M--来换步数加一 其实这样的话就有一个顺序而言保证每一次扩展被扩展那个都是最优解 所以保证了每一次都是最优 如果是最优的话 要用标
志位标志
刚刚想了一下 其实标志位放的位置也是很有技巧的 因为这道题目的步数是指从出发到达该点所需要的时间 (但是不包含终点,并且这个时间是最优的)
原创粉丝点击