A Knight's Journey
Time Limit: 1000MS | Memory Limit: 65536K | |
Total Submissions: 54285 | Accepted: 18381 |
Description
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.
Input
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, . . .
Output
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.
Sample Input
3
1 1
2 3
4 3
Sample Output
Scenario #1:
A1
Scenario #2:
impossible
Scenario #3:
A1B3C1A2B4C2A3B1C3A4B2C4
大概意思:
国际象棋中的马(可以走3*2的日字格),要走完(黑白都走)给定的棋盘大小上的所有格子,且不重复。有多条路可以选的话,选字典序(A,B,C,D.......)最小的路线,在这里是从左到右的顺序。在走的过程中有多个选择时,优先选择字典序小的路线。
输入:
首先第一行是有n个棋盘
接下来输入p q ,行数为p;列数为q (1 <= p * q <= 26)
棋盘从左上角(A1)开始(以确保之后得到的路径字典序是最小的),横向是A,B,C,D.... 竖直方向是1,2,3,4.....
输出:
Scenario #1:
走的顺序,A1代表第A列,第1行;没法走完则输出impossible
代码实现:
#include<iostream>
using namespace std;
#define MAX 27
bool visited[MAX][MAX]; //未走为false,走过为true
bool success = false;
struct Step{
char alpha, number;
} s[MAX];
int p, q; //x,y记录当前坐标
void jmp(int &x,int &y,int p, int q, int cases)
{
switch (cases) //字典序,要求跳至字母小的方向,优先向字母小(q)更的方向跳,q跳的相同,跳向p更小的方向
{
case 1:
x = p - 1;
y = q - 2;
break;
case 2:
x = p + 1;
y = q - 2;
break;
case 3:
x = p - 2;
y = q - 1;
break;
case 4:
x = p + 2;
y = q - 1;
break;
case 5:
x = p - 2;
y = q + 1;
break;
case 6:
x = p + 2;
y = q + 1;
break;
case 7:
x = p - 1;
y = q + 2;
break;
case 8:
x = p + 1;
y = q + 2;
break;
default:
break;
}
}
void dfs(int i, int j, int num)
{
s[num].number = i + '0';
s[num].alpha = j + 'A' - 1;
if (num == p*q)
{
success = true;
return;
}
for (int k = 1; k <= 8; k++)
{
int x, y; //这里遇到一个问题:x,y如果为全局变量,那么提交后答案就是错的,但是作为局部变量提交就是对的
//不知道有什么样的测试点在左右着答案,递归对全局变量的调用究竟是怎样的
//尽量避免全局变量的使用
jmp(x, y, i, j, k);
if (!visited[x][y] && x > 0 && x <= p && y > 0 && y <= q && !success) //尝试每一种情况1到8
{ //visited访问的时候不会越界?实际上会越界,但是前提是越界位置的的默认值是0,所以这个逻辑必须是visited[x][y]为false
visited[x][y] = true; //类似于visited[-1][-2],这样的地方的值默认为0,
dfs(x, y, num + 1); //如果走通了(走够了相应的步数),会在上面的if处return掉,走不通才会下来,继续走
visited[x][y] = false; //下面的一层没走通,撤销掉
}
}
}
int main()
{
int n;
cin >> n;
for (int i = 1; i <= n; i++)
{
success = false;
memset(visited, false, sizeof(visited)); //每次重新初始化一次棋盘状态
cin >> p >> q;
visited[1][1] = true; //起始点
dfs(1, 1, 1);
cout << "Scenario #" << i << ":" << endl;
if (success)
{
for (int j = 1; j <= p*q; j++)
{
cout << s[j].alpha << s[j].number;
}
cout << endl;
}
else
{
cout << "impossible" << endl;
}
cout << endl;
}
return 0;
}
总结
应尽量避免使用全局变量,因为不好查错的地方,这道题,我算法没变,只是将x,y先设置成全局变量,答案就错了,但x,y设置为局部变量之后就对了。