回溯算法
搜索与回溯是计算机解题中常用的算法,很多问题无法根据某种确定的计算法则来求解,可以利用搜索与回溯的技术求解。回溯是搜索算法中的一种控制策略。它的基本思想是:为了求得问题的解,先选择某一种可能情况向前探索,在探索过程中,一旦发现原来的选择是错误的,就退回一步重新选择,继续向前探索,如此反复进行,直至得到解或证明无解。
如迷宫问题:进入迷宫后,先随意选择一个前进方向,一步步向前试探前进,如果碰到死胡同,说明前进方向已无路可走,这时,首先看其它方向是否还有路可走,如果有路可走,则沿该方向再向前试探;如果已无路可走,则返回一步,再看其它方向是否还有路可走;如果有路可走,则沿该方向再向前试探。按此原则不断搜索回溯再搜索,直到找到新的出路或从原路返回入口处无解为止。
递归回溯法算法框架[一]
int Search(int k)
{
for (i=1;i<=算符种数;i++)
if (满足条件)
{
保存结果
if (到目的地) 输出解;
else Search(k+1);
恢复:保存结果之前的状态{回溯一步}
}
}
递归回溯法算法框架[二]
int Search(int k)
{
if (到目的地) 输出解;
else
for (i=1;i<=算符种数;i++)
if (满足条件)
{
保存结果;
Search(k+1);
恢复:保存结果之前的状态{回溯一步}
}
}
【例1】素数环:从1到20这20个数摆成一个环,要求相邻的两个数的和是一个素数。
【算法分析】
非常明显,这是一道回溯的题目。从1开始,每个空位有20种可能,只要填进去的数合法:与前面的数不相同;与左边相邻的数的和是一个素数。第20个数还要判断和第1个数的和是否素数。
【算法流程】
1、数据初始化; 2、递归填数:判断第i个数填入是否合法;
A、如果合法:填数;判断是否到达目标(20个已填完):是,打印结果;不是,递归填下一个;
B、如果不合法:选择下一种可能;
【参考程序】
1 #include<cstdio> 2 #include<iostream> 3 #include<cstdlib> 4 #include<cmath> 5 using namespace std; 6 bool b[21]={0}; 7 int total=0,a[21]={0}; 8 int search(int); //回溯过程 9 int print(); //输出方案 10 bool pd(int,int); //判断素数 11 int main() 12 { 13 search(1); 14 cout<<total<<endl; //输出总方案数 15 } 16 int search(int t) 17 { 18 int i; 19 for (i=1;i<=20;i++) //有20个数可选 20 if (pd(a[t-1],i)&&(!b[i])) //判断与前一个数是否构成素数及该数是否可用 21 { 22 a[t]=i; 23 b[i]=1; 24 if (t==20) { if (pd(a[20],a[1])) print();} 25 else search(t+1); 26 b[i]=0; //一会儿变1一会儿变0.。。那么他的存在到底是干嘛的叻 27 } 28 } 29 int print() 30 { 31 total++; 32 cout<<"<"<<total<<">"; 33 for (int j=1;j<=20;j++) 34 cout<<a[j]<<" "; 35 cout<<endl; 36 } 37 bool pd(int x,int y) 38 { 39 int k=2,i=x+y; 40 while (k<=sqrt(i)&&i%k!=0) k++; 41 if (k>sqrt(i)) return 1; 42 else return 0; 43 }
***总结来说呢。。回溯好像就是一种递归,满足了我就继续走,不满足掉头重新走啦。据说(好像就是)他能和神马图的联系在一起,但是很sad我不会图论哇。。打算求助小哥哥。。毕竟我老人家连例一代码还有不懂的地方。。好sad我貌似汉诺塔还没弄明白。。。OMG我都做了些神马。。。sadsad。。。。