楼主,按照你所给图片的思路做就好。思路大致总结如下:
#include<stdio.h>
#include<stack>
using namespace std;
struct Node //栈针
{
int i,j,k;
Node(int ii,int jj,int kk){
i = ii;
j = jj;
k = kk;
}
};
int dir[8][2]={ //题目所说的有8个方向
{-2,1},{-1,2},{1,2},{2,1},
{2,-1},{1,-2},{-1,-2},{-2,-1},
};
int n; //矩阵大小
int beginI,beginJ; //起点
stack<Node> s;//存放走过的路径
int grid[128][128];//grid[i][j] = 0 ; 表示格子(i,j) 还没有走过。
bool check(int i,int j)
{
if(i<0 || i>=n) return false;
if(j<0 || j>=n) return false;
return grid[i][j] == 0;
}
int main()
{
//输入5 , 1 ,1 结果正确
//输入4 , 1 , 1 结果正确
//其余情况未检查,仅供参考,谢谢。
scanf("%d",&n); //矩阵大小
scanf("%d%d",&beginI,&beginJ);
beginI --;
beginJ --; //个人习惯编码从0开始。
int allGrid = n*n;
s.push(Node(beginI,beginJ,0)); //这是起点
grid[beginI][beginJ] = 1;//表示已经走过这个格子了
//----------------core code begins.
while(s.size()<allGrid){
Node top = s.top(); //取栈顶
if(s.size()==1 && top.k==7){ //如果只剩起点,而且起点没办法继续走了,返回 no solution.
printf("no solution");
return 0;
}
if(top.k==7){ //如果top这个点 不能再继续走下去了,那么更新grid,出栈
grid[top.i][top.j] = 0;
s.pop();
}else{
// top 这点可能还可以继续往下走,那么试试看
bool hasNext = false;
for(int k=top.k+1;k<8;k++){//遍历8个方向
int nextI = dir[k][0] + top.i;
int nextJ = dir[k][1] + top.j;
if(check(nextI,nextJ)){
hasNext = true;
grid[nextI][nextJ] = 1;//标记
s.top().k = k;//记住更新栈顶元素的k
s.push(Node(nextI,nextJ,0));//这是我们找到的新的格子,压入栈中
break;
}
}
if(hasNext==false){//如果top这个点无法继续走下去了
if(s.size()==1){//如果只剩下起点,返回no solution。
printf("no solution");
return 0;
}
//并非只剩下 起点,还有希望,所以只需要去掉这个栈顶,返回前一步。
s.pop();
grid[top.i][top.j] = 0;
}
}
}
//-----core code ends.
// ---给每个格子 附上相应的步骤
while(allGrid>0){
Node top = s.top();
s.pop();
grid[top.i][top.j] = allGrid;
allGrid --;
}
//打印结果
printf("--exist solution--\n");
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
printf("%5d",grid[i][j]);
}
printf("\n");
}
return 0;
}
非常非常感谢您的解答!我定会仔细研究的,若是遇到问题,还望您能指教!
@GeekDragon: 好的,不客气。
@Jinke2017: 您好,我现在遇到一个问题。
我自己写了一个Stack类,没有用C++自带的stack类型;然后又写了一个结构体Knight,也就是您写的Node。
但是当我尝试写Stack<Knight> s; 的时候,编译器报错说"No matching function for call to Knight::Knight",我搜索了一下是构造函数的问题。但我在Stack类中定义了默认构造函数,为什么还会报错呢?
@GeekDragon: 请问你的Stack类是如何定义的呢?
@GeekDragon: 这里有个demo你参考一下
// template code example
#include<stdio.h>
using namespace std;
template <class numtype>
class Stack
{
public:
void push(numtype s){
printf("add success ... s.id == %d\n",s.i);
}
};
struct Node
{
int i,j,k;
Node(int ii,int jj,int kk){
i = ii;
j = jj;
k = kk;
}
};
int main(){
Stack<Node> ss;
ss.push(Node(1,1,1));
return 0;
}
如果你在学习c++的话,我觉得基本语法还是很重要的,所以有些必要的还是要熟练掌握。
虽然基础语法比较枯燥,所以还是要熟能生巧,多用就会熟悉了。因为我现在学java了,所以有些基本语法不清楚了,但是以前用的比较多,所以还能记住一些,希望你加油,多学多用,学和用相结合。
抱歉,这么晚才回复您。
您看,这是结构体:
这是Stack类的:
每次都是这里报错:
@GeekDragon: 试试给 Knight 这个类加默认的构造函数
@Jinke2017: 好了,现在编译是能过去了,但是最后的运行结果什么都打印不出来。
@GeekDragon: 我觉得应该是 Knight 没有加 空构造函数造成的。因为Stack() 构造函数那里调用了new T[_capacity] ,但是Knight没有空构造函数,所以报错的位置 报在了Stack()那里。
@Jinke2017:嗯嗯,确实是那里的问题。
@GeekDragon: 这时候就需要你 调试了,首先要保证你的 Stack 类没有问题。保证Stack没有问题之后要测试你的 逻辑代码有没有问题。
@Jinke2017: 嗯嗯,好的,我调试一下试试,非常感谢您!
@GeekDragon: 不客气~
@Jinke2017: 您好,我试了一下午发现是我写的Stack类有错误,目前已知是size函数有错误。
除此之外,还有几个问题想请教您:
1.在while循环的判断条件里,为什么是 s.size()<allGrid ?为什么不能换成 !s.empty() (判断栈是否为空)?
2.在最后“---给每个格子 附上相应的步骤 ”这个循环里,为什么每一个格子填的数值就是allGrid?
还请您指教。
@GeekDragon: 有一点我们要明确的,那就是栈里的元素是什么。
栈s的 每个栈元素 就是我们走过的 每一个格子。用结构体表示就是(i,j,k) : i是格子的横坐标,j是格子的纵坐标,k表示 当前这个格子采用第k种方法 走向下一个格子。
@Jinke2017: 原来是这样,真的太感谢您了,若是没有您的帮助,恐怕我要耗上好长时间。
@Jinke2017: 我在看其他博客时,发现有一种思想叫“启发式搜索”,一次看两步,那个我着实不理解,不知道您是否有所研究。
@GeekDragon: 启发式算法我并没有了解过,基本的印象是 对搜索的优化,根据一个函数去选择下一个搜索的节点,研究出这个函数是关键所在。我大学时有接触过算法方面的学习,但是很遗憾,启发式算法我没有深入了解,没有办法给你提供更有价值的答案。
@GeekDragon: @GeekDragon: 我刚搜索了一下,启发式有不少的文章可以供你参考,很抱歉这点没能帮上你。我说些题外话,如果你是大一大二刚接触算法,而且有兴趣继续往这方面学习。我希望你能由浅入深,从简单的贪心算法,到搜索,基础数据结构,再到动态规划,线段树,数论等等。像上面那道题就是属于数据结构和搜索这一块,如果你刚开始学,不建议你过早接触太过深奥的算法,从简单到复杂,逐渐去过渡比较好。在学习算法的过程中,也可以锻炼你的思维能力和编码能力,对于以后的项目开发也有极大的帮助。这只是个人建议,仅供参考,谢谢。
@Jinke2017: 感谢您的指导与点拨,晚辈听了犹如醍醐灌顶。
@GeekDragon: 只是一点个人建议,最后还是希望你加油。
@Jinke2017: 我给您发了条私信,您有时间的时候看一下,主要是向您请教一些学习方法。
递归实际上就是在调用栈。每递归一次,都是把一个函数压到栈中去。
循环加栈,可以代替递归。
大概就是这样吧。stack保存的不只是一个步骤,还有整个棋盘的状态。
while(stack.size()>0)
{
if(游离完了)
return stack;
if(不能再走了)
stack.pop();
if(可以有下一步)
stack.push(下一步);
}
好的,我先按照您的思路写一下试试,谢谢您!