整理:poj 基本搜索

参考:http://exp-blog.com/

         https://blog.csdn.net/consciousman/article/details/54613292

POJ2488 – A Knight’s Journey【骑士游历】 

大致题意

给出一个国际棋盘的大小,判断马能否不重复的走过所有格,并记录下其中按字典序排列的第一种路径。

经典的“骑士游历”问题,DFS水题一道 

解题思路
难度不大,但要注意的地方有3点:

1、 题目要求以”lexicographically”方式输出,也就是字典序…要以字典序输出路径,那么搜索的方向(我的程序是path()函数)就要以特殊的顺序排列了…这样只要每次从dfs(A,1)开始搜索,第一个成功遍历的路径一定是以字典序排列…

下图是搜索的次序,马的位置为当前位置,序号格为测试下一步的位置的测试先后顺序

按这个顺序测试,那么第一次成功周游的顺序就是字典序


2、国际象棋的棋盘,行为数字p;列为字母q

3、网上有同学说 这道题最后一组数据后是有空行的会PE…,我测试过,不会的,能AC
//Memory Time 
//240K   32MS 
 
#include<iostream>
using namespace std;
 
typedef class
{
    public:
        int row;
        char col;
}location;
 
int p,q;  //chess size = p*q
          //数字是行p,字母是列q
bool chess['Z'+1][27];
 
int x,y;  //返回值
void path(int i,int j,int num)  //ij为骑士当前在棋盘的位置 
{                               //num为骑士即将要跳到的位置序号
    switch(num)
    {
        case 1: {x=i-1; y=j-2; break;}     //注意这个尝试跳的顺序不能错   
        case 2: {x=i+1; y=j-2; break;}     //因为题目要求是字典序lexicographically输出
        case 3: {x=i-2; y=j-1; break;}     //这个顺序错了,必定WA
        case 4: {x=i+2; y=j-1; break;}
        case 5: {x=i-2; y=j+1; break;}
        case 6: {x=i+2; y=j+1; break;}
        case 7: {x=i-1; y=j+2; break;}
        case 8: {x=i+1; y=j+2; break;}
    }
    return;
}
 
bool DFS(location* way,int i,int j,int step)
{
    chess[i][j]=true;
    way[step].row=i;
    way[step].col=j;
    if(step==way[0].row)
        return true;
 
    for(int k=1;k<=8;k++)   //骑士从当前位置尝试跳到其他位置
    {
        path(i,j,k);
        int ii=x,jj=y;
        if(!chess[ii][jj] && ii>=1 && ii<=p && jj>='A' && jj<='A'+q-1)
            if(DFS(way,ii,jj,step+1))
                return true;
    }
 
    chess[i][j]=false;  //能执行到这步,说明前面跳的8步都不符合要求
    return false;       //即当前位置是错误位置,擦除记录返回上一步
}
 
int main(void)
{
    int test;
    cin>>test;
    int t=1;
    while(t<=test)
    {
        /*Initial*/
 
        memset(chess,false,sizeof(chess));
 
        cin>>p>>q;
        if(p==1 && q==1)      //范围缩窄,不要也能AC
        {
            cout<<"Scenario #"<<t++<<':'<<endl;
            cout<<"A1"<<endl<<endl;
            continue;
        }
        if(p*q>26 || p>=9 || q>=9 || p<=2 || q<=2)        //范围缩窄,不要也能AC
        {
            cout<<"Scenario #"<<t++<<':'<<endl;
            cout<<"impossible"<<endl<<endl;
            continue;
        }
 
        location* way=new location[p*q+1];   //记录走过的位置坐标
        way[0].row=p*q;   //记录总步数(棋盘总格子数)
 
        /*DFS*/
 
        bool flag=false;
        for(int j='A';j<='A'+q-1;j++)
        {
            for(int i=1;i<=p;i++)
                if(DFS(way,i,j,1))
                {
                    cout<<"Scenario #"<<t++<<':'<<endl;
 
                    for(int k=1;k<=way[0].row;k++)
                        cout<<way[k].col<<way[k].row;
                    cout<<endl<<endl;
                    flag=true;
                    break;
                }
                if(flag)
                    break;
        }
 
        if(!flag)
        {
            cout<<"Scenario #"<<t++<<':'<<endl;
            cout<<"impossible"<<endl<<endl;
        }
    }
    return 0;
}

2、poj3083
题目大意

给定一个迷宫,S是起点,E是终点,”#”是墙不可走,”.”可以走

先输出左转优先时,从S到E的步数

再输出右转优先时,从S到E的步数

最后输出S到E的最短步数

W为宽,列数 H为高,行数(3 <= w, h <= 40)

一个“S”和一个“E”将出现在迷宫中,它们将始终位于迷宫的一个边缘,而不是一个角落。迷宫将完全由墙壁('#')包围,唯一的开口是'S'和'E'。“S”和“E”之间还将至少隔一堵墙(“#”)。

Sample Input

2
8 8
########
#......#
#.####.#
#.####.#
#.####.#
#.####.#
#...#..#
#S#E####
9 5
#########
#.#.#.#.#
S.......E
#.#.#.#.#
#########

Sample Output

37 5 5
17 17 9

解题思路
DFS和BFS的综合题水题,难度不大,但是写代码时要注意几方面:

1、 左转、右转优先搜索时必须标记当前位置时的方向,我定义的方向是



最初的方向由起点S确定,而下一步的方向则由前一步的走向决定

例如 左边优先搜索:

当前位置的方向指向 1(向左),(这同时说明前一步是在第“3”的位置走过来的)

那么走下一步时,就要根据2103的顺序,先逐格确定当前位置周边的四格是否可行

若第一次确认2可行,就走到2,在位置2时的方向为2(向下)

若2不可行,则再确定1,若1可行,就走到1,在位置1时的方向为1(向左)

若1也不可行,则再确定0,若0可行,就走到0,在位置0时的方向为0(向上)

若0也不可行,说明进入了迷宫的死胡同,要从原路返回,走回3

右边优先搜索也同理。


根据我定义的方向,设当前位置为d,那么

左转,用数学式子表达就是 d=(d+1)%4

右转,用数学式子表达就是 d=(d+3)%4

我比较懒,在我的程序中,DFS和BFS都用了多入口的做法,有兴趣的同学可以利用我给出的这两个式子对代码进行优化。

这里有一点必须要注意的:

左边、右边优先搜索都不是找最短路,因此走过的路可以再走,无需标记走过的格

2、寻找最短路只能用BFS

因此在做第3问时别傻乎乎的又用DFS,DFS对于样例的输入确实和BFS得到的结果一样的,别以为样例PASS就提交了。。。所以我就说样例没代表性,学会测试数据很重要= =

注意有一点:

要求E的最短路,必须把迷宫模拟为树,S为根,找到E所在的层(树深),该层就是S到E的最短路,处理技巧就是在BFS时,令queue[tail]的depth等于对应的queue[head]的depth+1,详细见我的程序

把循环的次数作为深度就铁定错的
 

//Memory Time 
// 212K   0MS 
 
#include<iostream>
using namespace std;
 
typedef class
{
    public:
        int r,c;
        int depth;
}SE;
 
SE s,e; //起止点
int Lstep;  //左边优先搜索 时从S到E的总步数
int Rstep;  //右边优先搜索 时从S到E的总步数
int shortstep;  //S到E的最少总步数
 
bool maze[41][41]; //记录迷宫的“可行域”与“墙”
 
void DFS_LF(int i,int j,int d)    //左边优先搜索,i,j为当前点坐标,d为当前位置方向
{
    Lstep++;
    if(i==e.r && j==e.c)
        return;
 
    switch(d)
    {
        case 0:
            {
                if(maze[i][j-1])
                    DFS_LF(i,j-1,1);
                else if(maze[i-1][j])
                    DFS_LF(i-1,j,0);
                else if(maze[i][j+1])
                    DFS_LF(i,j+1,3);
                else if(maze[i+1][j])
                    DFS_LF(i+1,j,2);
                break;
            }
        case 1:
            {
                if(maze[i+1][j])
                    DFS_LF(i+1,j,2);
                else if(maze[i][j-1])
                    DFS_LF(i,j-1,1);
                else if(maze[i-1][j])
                    DFS_LF(i-1,j,0);
                else if(maze[i][j+1])
                    DFS_LF(i,j+1,3);
                break;
            }
        case 2:
            {
                if(maze[i][j+1])
                    DFS_LF(i,j+1,3);
                else if(maze[i+1][j])
                    DFS_LF(i+1,j,2);
                else if(maze[i][j-1])
                    DFS_LF(i,j-1,1);
                else if(maze[i-1][j])
                    DFS_LF(i-1,j,0);
                break;
            }
        case 3:
            {
                if(maze[i-1][j])
                    DFS_LF(i-1,j,0);
                else if(maze[i][j+1])
                    DFS_LF(i,j+1,3);
                else if(maze[i+1][j])
                    DFS_LF(i+1,j,2);
                else if(maze[i][j-1])
                    DFS_LF(i,j-1,1);
                break;
            }
    }
 
    return;
}
 
void DFS_RF(int i,int j,int d)    //右边优先搜索,i,j为当前点坐标,d为当前位置方向
{
    Rstep++;
    if(i==e.r && j==e.c)
        return;
 
    switch(d)
    {
        case 0:
            {
                if(maze[i][j+1])
                    DFS_RF(i,j+1,3);
                else if(maze[i-1][j])
                    DFS_RF(i-1,j,0);
                else if(maze[i][j-1])
                    DFS_RF(i,j-1,1);
                else if(maze[i+1][j])
                    DFS_RF(i+1,j,2);
                break;
            }
        case 1:
            {
                if(maze[i-1][j])
                    DFS_RF(i-1,j,0);
                else if(maze[i][j-1])
                    DFS_RF(i,j-1,1);
                else if(maze[i+1][j])
                    DFS_RF(i+1,j,2);
                else if(maze[i][j+1])
                    DFS_RF(i,j+1,3);
                break;
            }
        case 2:
            {
                if(maze[i][j-1])
                    DFS_RF(i,j-1,1);
                else if(maze[i+1][j])
                    DFS_RF(i+1,j,2);
                else if(maze[i][j+1])
                    DFS_RF(i,j+1,3);
                else if(maze[i-1][j])
                    DFS_RF(i-1,j,0);
                break;
            }
        case 3:
            {
                if(maze[i+1][j])
                    DFS_RF(i+1,j,2);
                else if(maze[i][j+1])
                    DFS_RF(i,j+1,3);
                else if(maze[i-1][j])
                    DFS_RF(i-1,j,0);
                else if(maze[i][j-1])
                    DFS_RF(i,j-1,1);
                break;
            }
    }
    return;
}
 
void BFS_MSS(int i,int j)    //最短路搜索
{
    bool vist[41][41]={false};
    SE queue[1600];
    int head,tail;
 
    queue[head=0].r=i;
    queue[tail=0].c=j;//queue[0]表示起点的坐标
    queue[tail++].depth=1;  //当前树深标记,这是寻找最短路的关键点
 
    vist[i][j]=true;
 
    while(head<tail)
    {
        SE x=queue[head++];//往下走一层
 
        if(x.r==e.r && x.c==e.c)
        {
            cout<<x.depth<<endl;
            return;
        }
 
        if(maze[x.r][x.c-1] && !vist[x.r][x.c-1])//左
        {
            vist[x.r][x.c-1]=true;//标记该点已经被访问
            queue[tail].r=x.r;//插入队列
            queue[tail].c=x.c-1;
            queue[tail++].depth=x.depth+1;//队列深度加一,队列指针右移
        }
        if(maze[x.r-1][x.c] && !vist[x.r-1][x.c])//上
        {
            vist[x.r-1][x.c]=true;
            queue[tail].r=x.r-1;
            queue[tail].c=x.c;
            queue[tail++].depth=x.depth+1;
        }
        if(maze[x.r][x.c+1] && !vist[x.r][x.c+1])//右
        {
            vist[x.r][x.c+1]=true;
            queue[tail].r=x.r;
            queue[tail].c=x.c+1;
            queue[tail++].depth=x.depth+1;
        }
        if(maze[x.r+1][x.c] && !vist[x.r+1][x.c])//下
        {
            vist[x.r+1][x.c]=true;
            queue[tail].r=x.r+1;
            queue[tail].c=x.c;
            queue[tail++].depth=x.depth+1;
        }
    }
    return;
}
 
int main(int i,int j)
{
    int test;
    cin>>test;
    while(test--)
    {
        int direction;  //起点S的初始方向
        int w,h;  //size of maze
        cin>>w>>h;
 
        /*Initial*/
 
        Lstep=1;
        Rstep=1;
        memset(maze,false,sizeof(maze));
 
        /*Structure the Maze*/
 
        for(i=1;i<=h;i++)
            for(j=1;j<=w;j++)
            {
                char temp;
                cin>>temp;
                if(temp=='.')//可以走的路
                    maze[i][j]=true;
                if(temp=='S')//起点
                {
                    maze[i][j]=true;
                    s.r=i;
                    s.c=j;
 
                    if(i==h)//起点在最后一行
                        direction=0;
                    else if(j==w)//起点在最后一列
                        direction=1;
                    else if(i==1)//起点在第一行
                        direction=2;
                    else if(j==1)//起点在第一列
                        direction=3;
                }
                if(temp=='E')//终点
                {
                    maze[i][j]=true;
                    e.r=i;
                    e.c=j;
                }
            }
 
        /*Left First Search*/
 
        switch(direction)
        {
            case 0: {DFS_LF(s.r-1,s.c,0); break;}//左边优先搜索,s.r-1,s.c为当前点坐标,d为当前位置方向
            case 1: {DFS_LF(s.r,s.c-1,1); break;}
            case 2: {DFS_LF(s.r+1,s.c,2); break;}
            case 3: {DFS_LF(s.r,s.c+1,3); break;}
        }
        cout<<Lstep<<' ';
 
        /*Right First Search*/
 
        switch(direction)
        {
            case 0: {DFS_RF(s.r-1,s.c,0); break;}
            case 1: {DFS_RF(s.r,s.c-1,1); break;}
            case 2: {DFS_RF(s.r+1,s.c,2); break;}
            case 3: {DFS_RF(s.r,s.c+1,3); break;}
        }
        cout<<Rstep<<' ';
 
        /*Most Short Step Search*/
 
        BFS_MSS(s.r,s.c);
 
    }
    return 0;
} 
 
#include <cstdio>
#include <cstring>
 
int w, h, c, a;
int Sx, Sy, Ex, Ey;
int cnt, flag, tag;
int dir[4][2] = {0, -1, -1, 0, 0, 1, 1, 0};
char maze[50][50];
int vis[50][50];
int que[2500][2];
 
void DFS(int x, int y, int cnt) {
    if (maze[x][y] == 'E') {
        printf("%d ", cnt);
        tag = 0;
        return ;
    }
    if (tag) for (int i = a+c, j = 0; j < 4; j++, i -= c) {
        if (i < 0) i = 3;
        if (i > 3) i = 0;
        int tx = x + dir[i][0];
        int ty = y + dir[i][1];
        if (tx > h || tx < 1 || ty > w || ty < 1) continue;
        if (tag && !vis[tx][ty] && maze[tx][ty] != '#') {
            a = i;
            DFS(tx, ty, cnt+1);
        }
    }
}
 
void BFS() {
    int fir = 0, sec = 0;
    que[sec][0] = Sx;
    que[sec++][1] = Sy;
    int step = 1;
    while(fir < sec && !vis[Ex][Ey]) {
        int tmp = sec;
        step++;
        while(fir < tmp && !vis[Ex][Ey]) {
            int x = que[fir][0];
            int y = que[fir++][1];
            for(int i = 0; i < 4; i++) {
                int tx = x + dir[i][0];
                int ty = y + dir[i][1];
                if (tx > h || tx < 1 || ty > w || ty < 1) continue;
                if(!vis[tx][ty] && maze[tx][ty] != '#') {
                    que[sec][0] = tx;
                    que[sec++][1] = ty;
                    vis[tx][ty] = 1;
                }
            }
        }
    }
    printf("%d\n", step);
}
 
int main() {
    int t, i, j;
    scanf("%d", &t);
    while (t--) {
        memset(maze, 0, sizeof(maze));
        memset(vis, 0, sizeof(vis));
        scanf("%d %d", &w, &h);
        getchar();
        for (i = 1; i <= h; i++) {
            for (j = 1; j <= w; j++) {
                scanf("%c", &maze[i][j]);
                if (maze[i][j] == 'S') Sx = i, Sy = j;
                else if (maze[i][j] == 'E') Ex = i, Ey = j;
            }
            getchar();
        }
        for (i = 0; i < 4; i++)
            if (maze[Sx+dir[i][0]][Sy+dir[i][1]] == '.') break;
        vis[Sx][Sy] = 1;
        a = i; tag = 1; c = -1;
        DFS(Sx, Sy, 1);
        a = i; c = 1; tag = 1;
        DFS(Sx, Sy, 1);
        BFS();
    }
    return 0;
}

 

POJ3009 – Curling 2.0

大致题意
要求把一个冰壶从起点“2”用最少的步数移动到终点“3”

其中0为移动区域,1为石头区域,冰壶一旦想着某个方向运动就不会停止,也不会改变方向(想想冰壶在冰上滑动),除非冰壶撞到石头1 或者 到达终点 3
注意的是:

冰壶撞到石头后,冰壶会停在石头前面,此时(静止状态)才允许改变冰壶的运动方向,而该块石头会破裂
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值