A Knight's Journey
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 Source
TUD Programming Contest 2005, Darmstadt, Germany
|
题意:给出制定规格的网格,问马能不能不重复的全部走完,并按字典序输出路径。
解题思路:这题显然用DFS会简单一些。开始的时候,我想的是:既然是要把所有的格子遍历一遍,而且输出的结果要以字典序的顺序输出,所以只需要调好搜索的顺序,并用数组存下路径即可。然后,经过我的多次调试,终于过了样例,以下是我的最初代码
#include <stdio.h>
#include <memory.h>
#include <string.h>
#define maxn 30
typedef struct road
{
char p;
char q;
} T;
T arr[700];
int flag[maxn][maxn],m,n,a=0;
void dfs(int r,int s)
{
if(r<0||r>=m||s<0||s>=n) return;
if(flag[r][s]!=0) return;
flag[r][s]=1;
arr[a].p=s+'A';
arr[a].q=r+'1';
a++;
dfs(r+2,s+1);
dfs(r+2,s-1);
dfs(r-2,s-1);
dfs(r-2,s+1);
dfs(r+1,s+2);
dfs(r+1,s-2);
dfs(r-1,s+2);
dfs(r-1,s-2);
}
int main()
{
//freopen("in.txt","r",stdin);
int t;
scanf("%d",&t);
for(int k=1; k<=t; k++)
{
a=0;
memset(flag,0,sizeof(flag));
scanf("%d%d",&m,&n);
printf("Scenario #%d:\n",k);
dfs(0,0);
int f=1;
for(int i=0; i<m; i++)
for(int j=0; j<n; j++)
if(flag[i][j]==0) f=0;
if(!f) printf("impossible\n");
else
{
for(int i=0; i<a; i++)
printf("%c%c",arr[i].p,arr[i].q);
printf("\n");
}
}
return 0;
}
结果不尽人意,果断被系统判了WA。debug调试一次后,我就明白了自己错在哪里。走到错误的路的时候,虽然搜索的进度会返回,但是flag已经标记,没有被改回来,所以后续搜索的时候会误以为此处已经在整条路径中。于是我就改用了回溯法。在走到错路的时候,返回时把flag还原回去,然后在dfs函数参数里加了路径的下标,这样保证每次存储的时候都是正确的路(就算前面存的是错误的回溯之后会重新赋值)。修改后,我的代码如下
#include <stdio.h>
#include <memory.h>
#include <string.h>
#define maxn 30
typedef struct road
{
char p;
char q;
} T;
T arr[700];
int flag[maxn][maxn],m,n,a=0,success=0,vis[2][8]= {{-2,-2,-1,-1,1,1,2,2},{-1,1,-2,2,-2,2,-1,1}};
void dfs(int x,int y,int a)
{
if(success) return;
arr[a].p=x+'A';
arr[a].q=y+'1';
if(a==m*n)
{
success=1;
return;
}
int yy,xx;
for(int i=0; i<8; i++)
{
xx=x+vis[0][i];
yy=y+vis[1][i];
if(flag[xx][yy]==1) continue;
if(yy<0||yy>=m||xx<0||xx>=n) continue;
flag[xx][yy]=1;
dfs(xx,yy,a+1);
flag[xx][yy]=0;
}
}
int main()
{
//freopen("in.txt","r",stdin);
int t;
scanf("%d",&t);
for(int k=1; k<=t; k++)
{
a=0;
memset(flag,0,sizeof(flag));
scanf("%d%d",&m,&n);
printf("Scenario #%d:\n",k);
success=0;
flag[0][0]=1;
dfs(0,0,1);
if(!success) printf("impossible\n");
else
{
for(int i=1; i<=m*n; i++)
printf("%c%c",arr[i].p,arr[i].q);
printf("\n");
}
printf("\n");
}
return 0;
}
一次AC。