http://202.204.102.161/showproblem.php?problemid=1190
这是第一次解决回溯的问题,之前也看过相关的一些书,不过由于递归函数理解的不好,也就一直没有信心去做回溯的问题。还好,没有想象中的那么难。真的是只有实际动手才知道会不会。
题意:有些像八皇后问题,就不多介绍了。
1、做题的过程中也遇到了几个问题,递归调用函数的时候开始写的是dfs(hang+1),后来发现这样写是错误的,原因是hang的值并没有发生变化,改成这样就对了dfs(++hang)。
2、刚开始写的是hang==len ,后来发现了错误改成了hang==len+1。这个地方要len+1,因为hang表示刚进入当前hang,这时还没有对当前的行进行分析讨论,当讨论完最后一行进入的应该是len+1行。
3、判断当前行的点的位置时,要与之前所有行进行讨论,而不仅只是前一行。这里要用到循环语句。
此外,通过第一次做的这道回溯算法题,对dfs和递归调用函数还有解答树的一些概念了解的更深刻了。回溯法就像是在一棵树上搜索,当前面没有路了,这时候往往会遇到return 语句,结束当前的调用,返回上一级,如果上一级还有路可以走,就走下去,若没有,则在程序中还会遇到return 语句,继续返回上一层,直到有路可走或找到结果。
以前一直对回溯的过程理解的不太好,通过做题,现在的理解就是递归调用函数(例如下面代码中的dfs(hang))之后进行回溯,一般是对递归函数之前的一些恢复操作。比如调用函数前面是hang++,后面要执行hang--;还有就是之前不理解递归调用中的return语句,一些问题中return是要返回具体的数值,这是题目所要求的。而本道题的return仅仅是结束当前这一层的递归函数,没有什么实际意义。
</pre><p></p><p><span style="font-size:18px"></span></p><p><span style="font-size:18px"></span></p><pre code_snippet_id="413430" snippet_file_name="blog_20140701_2_5707023" name="code" class="cpp">#include<iostream>
using namespace std;
int len;
int a[15];
int sum=0,ans=0;
int visit[15];
bool safe(int hang,int temp)
{
for(int i=1; i<=hang-1; i++)
{
if(a[i]+i==temp+hang)
return 0;
if(a[i]-i==temp-hang)
return 0;
if(a[i]==temp)
return 0;
}
return 1;
}
int dfs(int hang)
{
if(hang==len+1) //这个地方要len+1,因为hang表示刚进入当前hang,还没有对当前行进行讨论
{
sum++;
if(ans==3)
return 0;
cout<<a[1];
for(int i=2; i<=len; i++)
cout<<" "<<a[i];
cout<<endl;
ans++;
return 0;
}
for(int i=1; i<=len; i++)
{
if(hang!=1)
{
if(!safe(hang,i))
continue;
}
a[hang]=i;
hang++; // 其实这三行可以简写为 dfs(hang+1) 这样也可以的,之前第一次写DFS回溯难免拙计
dfs(hang); //之前写的是hang+1,结果错了,因为hang这个值本身并没有变化
hang--; //
}
return 0;
}
int main()
{
cin>>len;
dfs(1);
if(sum>=3)
cout<<sum<<endl;
return 0;
}