参考 http://user.qzone.qq.com/289065406/blog/1303350143
一步一步地写出结果。
第一步是如何判断能否遍历整个棋盘。对于输出路径先不予考虑。由于题目要求字典序遍历,因此每一步,按照从左到右,从上到下的顺序试,第一次得到的必然是字典序。
step函数就是这个作用。
当第k步执行到if时,先判断这个格子是否走过,再看是否越界。然后就看它的下一步是否能够成功。如果能成功,第k部就返回true,使第k步的上一步(k-1)继续返回true。这就是递归过程。如果能执行到
就说明这一步的下一步不能成功遍历,那么相应的这一步也就不能成功遍历。那么把这一步走过的记号(vis)变成没有访问过,回到上一步继续试。在接下来的主函数里面,判断是否能够成功。
前面两个if用于缩小范围。可以看到每个impossible后面都有一个数字作记号,这样在输出impossible 的时候可以知道到底是哪个if使它输出impossible的。
当然,这个主函数是有bug的,如果你第一次输入4 3,第二次再输入4 3,那么第一次会输出possible,第二次会输出impossible。还有其他的各种各样的bug。反正是一个基本的程序,只要能完成基本的功能,其他的bug下面再慢慢修补。
下面一步就是记录每步走过的地方并且输出。然后就是修补一些bug。
对于上面说的4 3的bug,加上memset函数就行了。
对于走过的路径的记录是在dfs 函数里面实现的。每走一步就记录一次,如果这一步没有成功,就会返回上一步,然后再向下的时候就会把错误的值给覆盖掉。
这道题,据说是水题……可是对我来说,还是有点难度。毕竟对于递归调用还是很不熟练。我把我做这道题的时候的步骤简单的写了下来。其中参考了别人的日志,但是我是在看了一遍别人的东西以后,在自己写的过程中绝对不看别人的东西。希望能够有些长进。
一步一步地写出结果。
第一步是如何判断能否遍历整个棋盘。对于输出路径先不予考虑。由于题目要求字典序遍历,因此每一步,按照从左到右,从上到下的顺序试,第一次得到的必然是字典序。
step函数就是这个作用。
然后是一个递归函数,函数结束的条件是走的步数等于棋盘的格子数。vis用于记录每个格子是否到达过。for循环就是使走的下一步按照从左到右,从上到下的顺序走。
for(int k=1;k<=8;++k){
step(i,j,k);
int ii=x,jj=y;
if(!vis[ii][jj]&&ii>=1&&jj>=1&&ii<=p&&jj<=q)
if(dfs(ii,jj,s+1))return true;
}
当第k步执行到if时,先判断这个格子是否走过,再看是否越界。然后就看它的下一步是否能够成功。如果能成功,第k部就返回true,使第k步的上一步(k-1)继续返回true。这就是递归过程。如果能执行到
vis[i][j]=false;
return false;
就说明这一步的下一步不能成功遍历,那么相应的这一步也就不能成功遍历。那么把这一步走过的记号(vis)变成没有访问过,回到上一步继续试。在接下来的主函数里面,判断是否能够成功。
前面两个if用于缩小范围。可以看到每个impossible后面都有一个数字作记号,这样在输出impossible 的时候可以知道到底是哪个if使它输出impossible的。
当然,这个主函数是有bug的,如果你第一次输入4 3,第二次再输入4 3,那么第一次会输出possible,第二次会输出impossible。还有其他的各种各样的bug。反正是一个基本的程序,只要能完成基本的功能,其他的bug下面再慢慢修补。
#include<iostream>
using namespace std;
int vis[26][26];
int x,y;
int p,q;
int step(int i,int j,int k){
switch(k){
case 1:{x=i-1;y=j-2;break;}
case 2:{x=i+1;y=j-2;break;}
case 3:{x=i-2;y=j-1;break;}
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;}
}
}
int dfs(int i,int j,int s){
vis[i][j]=true;
if(s==p*q)return true;
for(int k=1;k<=8;++k){
step(i,j,k);
int ii=x,jj=y;
if(!vis[ii][jj]&&ii>=1&&jj>=1&&ii<=p&&jj<=q)
if(dfs(ii,jj,s+1))return true;
}
vis[i][j]=false;
return false;
}
int main(){
int n;
cin>>n;
for(;n;n--){
cin>>p>>q;
if(p==1||q==1){
cout<<"Scenario #"<<n<<':'<<endl;
cout<<"impossible"<<endl;cout<<"1"<<endl;
continue;
}
if(p*q>26){
cout<<"Scenario #"<<n<<':'<<endl;
cout<<"impossible2"<<endl;
continue;
}
if(dfs(1,1,1)){
cout<<"Scenario #"<<n<<':'<<endl;
cout<<"possible"<<endl;
}
else {
cout<<"Scenario #"<<n<<':'<<endl;
cout<<"impossible3"<<endl;
}
}
}
下面一步就是记录每步走过的地方并且输出。然后就是修补一些bug。
对于上面说的4 3的bug,加上memset函数就行了。
对于走过的路径的记录是在dfs 函数里面实现的。每走一步就记录一次,如果这一步没有成功,就会返回上一步,然后再向下的时候就会把错误的值给覆盖掉。
#include<iostream>
#include<string.h>
using namespace std;
int row[26];
char col[26];
int vis[26][26];
int x,y;
int p,q;
int step(int i,int j,int k){
switch(k){
case 1:{x=i-1;y=j-2;break;}
case 2:{x=i+1;y=j-2;break;}
case 3:{x=i-2;y=j-1;break;}
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;}
}
}
int dfs(int i,int j,int s){
vis[i][j]=true;
row[s]=i;
col[s]='A'+j-1;
if(s==p*q)return true;
for(int k=1;k<=8;++k){
step(i,j,k);
int ii=x,jj=y;
if(!vis[ii][jj]&&ii>=1&&jj>=1&&ii<=p&&jj<=q)
if(dfs(ii,jj,s+1))return true;
}
vis[i][j]=false;
return false;
}
int main(){
int n;
cin>>n;
for(int z=1;z<=n;z++){
cin>>p>>q;
memset(vis,false,sizeof(vis));
if(p*q>26){
cout<<"Scenario #"<<z<<':'<<endl;
cout<<"impossible"<<endl;
continue;
}
if(dfs(1,1,1)){
cout<<"Scenario #"<<z<<':'<<endl;
for(int i=1;i<=p*q;++i){
cout<<col[i]<<row[i];
}
cout<<endl;
}
else {
cout<<"Scenario #"<<z<<':'<<endl;
cout<<"impossible"<<endl;
}
cout<<endl;
}
}
这道题,据说是水题……可是对我来说,还是有点难度。毕竟对于递归调用还是很不熟练。我把我做这道题的时候的步骤简单的写了下来。其中参考了别人的日志,但是我是在看了一遍别人的东西以后,在自己写的过程中绝对不看别人的东西。希望能够有些长进。