002: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
思路分析:
按字典序DFS查找一条可以周游全棋盘的路径。
1.需要标记已经过的路径——color数组
2.需要按字典顺序遍历——dx,dy数组
3.需要输出路径,即需要保存路径——path数组(保存每个点的i,j)
4.只需要找一条路径,故找到后需要退出标志——flag
5.把数字转化为字符的方法——char(0+‘A’)为’A’
写法1
在Dfs函数内找到后直接输出;
条件写在遍历循环内——代表对接下来的循环所作的要求;
#include<cstring>
#include<iostream>
using namespace std;
int color[30][30];
struct path{
int I,J;
}path[1000];
int N;
int M;
int dx[8]={-2,-2,-1,-1,1,1,2,2}; //字典顺序
int dy[8]={-1,1,-2,2,-2,2,-1,1};
int flag=0;
int n;
void Dfs(int i, int j,int depth){ //三个形参——行、列、经过的点数
path[depth].I=i;
path[depth].J=j;
if (N*M==depth) { //相等即已遍历所有的点
flag=1; //flag归1——代表退出循环到最上层,输出找到的路径
for (int k=1;k<=N*M;k++){
cout<<char(path[k].I+'A')<<path[k].J+1;
}
cout<<endl;
cout<<endl;
}
for (int k=0;k<8;k++){
if (flag==1) return; //若已找到路径——全部弹出
if (color[i+dx[k]][j+dy[k]]) continue;
//若下一个位置已查询过——弹出
if(i+dx[k]<0||i+dx[k]>=N||j+dy[k]<0||j+dy[k]>=M) continue;
//若下一个位置超出范围——弹出
color[i+dx[k]][j+dy[k]]=1;
Dfs(i+dx[k],j+dy[k],depth+1);
color[i+dx[k]][j+dy[k]]=0;
}
}
int main (){
cin>>n;
for (int t=1;t<=n;t++){
cin>>M>>N;
cout<<"Scenario #"<<t<<":"<<endl;
memset(color,0,sizeof color); //初始化color
color[0][0]=1; //出发点设为已标记
memset(path,0,sizeof path); //初始化路径数组
flag=0;
Dfs(0,0,1); //从0,0出发周游全图
if (flag==0){ //flag==0说明没有找到路径
cout<<"impossible"<<endl;
cout<<endl;
}
}
}
写法2:
用Dfs函数找到所需路径保存至path,主函数中输出path;
条件写在遍历循环之外——代表对当前函数做的操作;
//骑士周游
#include<cstring>
#include<iostream>
using namespace std;
int color[30][30];
struct path{
int I,J;
}path[1000];
int N;
int M;
int dx[8]={-2,-2,-1,-1,1,1,2,2}; //字典顺序
int dy[8]={-1,1,-2,2,-2,2,-1,1};
int flag=0;
void Dfs(int i, int j,int depth){
if(flag==1) return; //若当前已找到路径————直接弹出
if (color[i][j]) return; //若当前点已遍历————直接弹出
if(i<0||i>=N||j<0||j>=M) return; //若当前点超出范围————直接弹出
if (N*M==depth+1) { //找到第一条路径的时候
flag=1; //标志调整为1
path[depth].I=i; //记录该点行数
path[depth].J=j; //记录该点列数
return; //弹出
}
//若都不满足上述条件
path[depth].I=i; //记录该点
path[depth].J=j; //记录该点
color[i][j]=1; //标为已遍历
for (int k=0;k<8;k++){ //由该点向四周寻找
Dfs(i+dx[k],j+dy[k],depth+1);
}
color[i][j]=0; //标为未遍历
//path会被接下来的循环覆盖————初不初始化没有啥关系
}
int n;
int main (){
cin>>n;
for (int t=1;t<=n;t++){
cin>>M>>N;
cout<<"Scenario #"<<t<<":"<<endl;
memset(color,0,sizeof color);
flag=0; //初始化标志
Dfs(0,0,0);
if (flag==0){
cout<<"impossible"<<endl;
cout<<endl;
}
else{
for (int k=0;k<N*M;k++){
cout<<char(path[k].I+'A')<<path[k].J+1;
//把数字转化为字符的方法
}
cout<<endl;
cout<<endl;
}
}
}