程序设计实习MOOC/第十五周编程作业/B:A Knight's Journey(TUD Programming Contest 2005, Darmstadt, Germany)

题目:B:A Knight's Journey
总时间限制: 1000ms 内存限制: 65536kB
描述
Background
The knight is getting bored of seeing the same black and white squares again and again and has decided to make a journey
around the world. Whenever a knight moves, it is two squares in one direction and one square perpendicular to this. The world of a knight is the chessboard he is living on. Our knight lives on a chessboard that has a smaller area than a regular 8 * 8 board, but it is still rectangular. Can you help this adventurous knight to make travel plans?

Problem
Find a path such that the knight visits every square once. The knight can start and end on any square of the board.
输入
The input begins with a positive integer n in the first line. The following lines contain n test cases. Each test case consists of a single line with two positive integers p and q, such that 1 <= p * q <= 26. This represents a p * q chessboard, where p describes how many different square numbers 1, . . . , p exist, q describes how many different square letters exist. These are the first q letters of the Latin alphabet: A, . . .
输出
The output for every scenario begins with a line containing "Scenario #i:", where i is the number of the scenario starting at 1. Then print a single line containing the lexicographically first path that visits all squares of the chessboard with knight moves followed by an empty line. The path should be given on a single line by concatenating the names of the visited squares. Each square name consists of a capital letter followed by a number.
If no such path exist, you should output impossible on a single line.
样例输入
3
1 1
2 3
4 3
样例输出
Scenario #1:
A1

Scenario #2:
impossible

Scenario #3:
A1B3C1A2B4C2A3B1C3A4B2C4


解题思路:深度优先搜索,值得注意的是要按字典序方向,所以八个方向的顺序固定!

#include<iostream>
#include<string.h>
#include<queue>
using namespace std;

struct Step
{
    int row;//对应某一行 
    int col;//对应某一列 
    Step(int _r, int _c):row(_r),col(_c){}
};

int p, q, counts, visited[8][8];
bool flag = false;//标识是否有路线

void DFS(queue<Step> s, int k)//分别表示已走过的路线、还有多少个位置没有走过
{
    if(k == 0)//找到路线了,则输出路线,修改标识位 
    {
        flag = true;
        
        cout << "Scenario #" << counts << ":" <<endl;
        while(s.size() != 0)
        {
            Step step = s.front();//从队列(路线)中取出队头元素
            s.pop();
            char alphabet[] = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 
            'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'};
            cout << alphabet[step.col]/*输出列号从A开始*/ << step.row + 1;//要加一,因为程序中是从0开始计数,而输出中是以1开始 
        }
        cout <<endl;
        return;
    }
    //来到这里,表明前面没有return,即k不等于0,此时,考察往八个方向走的情况
    Step step = s.back();//读取上一步的位置
    int row, col;
    row = step.row;
    col = step.col;
    
    //由于要字典序输出,所以八个方向顺序一定不能错 
    if(!flag && !visited[row - 1][col - 2] && row - 1 >= 0 && col - 2 >= 0)//当前还未找到一条可行路线且步走法可行 
    {
        visited[row - 1][col - 2] = 1;
        queue<Step> s_temp = s;
        s_temp.push(Step(row - 1, col - 2));//将该步加入路线中,形参拷贝传递,所以不同路线之间不会影响 
        DFS(s_temp, k - 1);//继续下一步 
        
        visited[row - 1][col - 2] = 0;//回溯,不走该步,由于我是用s_temp来存储当前步的,
        //所以对于换一条路线,用的s仍是不变的,所以不会有影响 
    }
    
    if(!flag && !visited[row + 1][col - 2] && row + 1 < p && col - 2 >= 0)//当前还未找到一条可行路线且步走法可行
    {
        visited[row + 1][col - 2] = 1;
        queue<Step> s_temp = s;
        s_temp.push(Step(row + 1, col - 2));//将该步加入路线中,形参拷贝传递,所以不同路线之间不会影响 
        DFS(s_temp, k - 1);//继续下一步 
        
        visited[row + 1][col - 2] = 0;
    }
    
    if(!flag && !visited[row - 2][col - 1] && row - 2 >= 0 && col - 1 >= 0)//当前还未找到一条可行路线且步走法可行
    {
        visited[row - 2][col - 1] = 1;
        queue<Step> s_temp = s;
        s_temp.push(Step(row - 2, col - 1));//将该步加入路线中,形参拷贝传递,所以不同路线之间不会影响 
        DFS(s_temp, k - 1);//继续下一步
         
        visited[row - 2][col - 1] = 0;
    }
    
    if(!flag && !visited[row + 2][col - 1] && row + 2 < p && col - 1 >= 0)//当前还未找到一条可行路线且步走法可行
    {
        visited[row + 2][col - 1] = 1;
        queue<Step> s_temp = s;
        s_temp.push(Step(row + 2, col - 1));//将该步加入路线中,形参拷贝传递,所以不同路线之间不会影响 
        DFS(s_temp, k - 1);//继续下一步 
        
        visited[row + 2][col - 1] = 0;
    }
    
    if(!flag && !visited[row - 2][col + 1] && row - 2 >= 0 && col + 1 < q)//当前还未找到一条可行路线且步走法可行
    {
        visited[row - 2][col + 1] = 1;
        queue<Step> s_temp = s;
        s_temp.push(Step(row - 2, col + 1));//将该步加入路线中,形参拷贝传递,所以不同路线之间不会影响 
        DFS(s_temp, k - 1);//继续下一步 
        
        visited[row - 2][col + 1] = 0;
    }
    
    if(!flag && !visited[row + 2][col + 1] && row + 2 < p && col + 1 < q)//当前还未找到一条可行路线且步走法可行
    {
        visited[row + 2][col + 1] = 1;
        queue<Step> s_temp = s;
        s_temp.push(Step(row + 2, col + 1));//将该步加入路线中,形参拷贝传递,所以不同路线之间不会影响 
        DFS(s_temp, k - 1);//继续下一步 
        
        visited[row + 2][col + 1] = 0;
    }
       
    if(!flag && !visited[row - 1][col + 2] && row - 1 >= 0 && col + 2 < q)//当前还未找到一条可行路线且步走法可行
    {
        visited[row - 1][col + 2] = 1;
        queue<Step> s_temp = s;
        s_temp.push(Step(row - 1, col + 2));//将该步加入路线中,形参拷贝传递,所以不同路线之间不会影响 
        DFS(s_temp, k - 1);//继续下一步 
        
        visited[row - 1][col + 2] = 0;
    }
    
    if(!flag && !visited[row + 1][col + 2] && row + 1 < p && col + 2 < q)//当前还未找到一条可行路线且步走法可行
    {
        visited[row + 1][col + 2] = 1;
        queue<Step> s_temp = s;
        s_temp.push(Step(row + 1, col + 2));//将该步加入路线中,形参拷贝传递,所以不同路线之间不会影响 
        DFS(s_temp, k - 1);//继续下一步 
        
        visited[row + 1][col + 2] = 0;
    }  
}

int main()
{
    int n; 
    queue<Step> s;//使用队列存储每一步走到的位置 
    counts = 0;
    cin >> n;
    
    while(counts != n)
    {
        counts++;
        flag = false;
        memset(visited, 0, sizeof(visited));
        cin >> p >> q;
        
        for(int i = 0; i < p; i++)
        {
            for(int j = 0; j < q; j++)
            {
                s.push(Step(i, j));//(i,j)作为起始位置
                visited[i][j] = 1;
                DFS(s, p * q - 1);//还有p*q-1个位置没有走过
                
                visited[i][j] = 0;//回溯,考察下一个起始位置 
                s.pop();//由于s是作为形参复制拷贝传递进DFS去,所以在main函数中的s就只有第一个起始位置,
                //所以这里弹出第一个起始位置即可,s就清空了,方便考察for循环中下一个起始位置
                if(flag)//找到一条路线了,在DFS中已经输出该路线了,跳出循环 
                    break;
            }
            if(flag)//找到一条路线了,在DFS中已经输出该路线了,跳出循环 
                break;
        }
        if(! flag)//for循环结束都没有找到路线,则输出impossible 
            cout << "Scenario #" << counts << ":" <<endl << "impossible" <<endl;
        cout << endl;
    }
    
    system("pause");
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值