回溯法采用的搜索策略_17图的搜索算法之回溯法

回 溯 法

回溯算法实际是一个类似枚举的搜索尝试方法,它的主题思想是在搜索尝试中找问题的解,当不满足求解条件就”回溯”返回,尝试别的路径。回溯算法是尝试搜索算法中最为基本的一种算法,其采用了一种“走不通就掉头”的思想,作为其控制结构。

【例1】八皇后问题模型建立

要在8*8的国际象棋棋盘中放八个皇后,使任意两个皇后都不能互相吃掉。规则:皇后能吃掉同一行、同一列、同一对角线的任意棋子。如图5-12为一种方案,求所有的解。

模型建立

不妨设八个皇后为xi,她们分别在第i行(i=1,2,3,4……,8),这样问题的解空间,就是一个八个皇后所在列的序号,为n元一维向量(x1,x2,x3,x4,x5,x6,x7,x8),搜索空间是1≤xi≤8(i=1,2,3,4……,8),共88个状态。约束条件是八个(1,x1),(2,x2) ,(3,x3),(4,x4) ,(5,x5), (6,x6) , (7,x7), (8,x8)不在同一行、同一列和同一对角线上。

虽然问题共有88个状态,但算法不会真正地搜索这么多的状态,因为前面已经说明,回溯法采用的是“走不通就掉头”的策略,而形如(1,1,x3,x4, x5,x6,x7,x8)的状态共有86个,由于1,2号皇后

在同一列不满足约束条件,回溯后这86个状态是不会搜索的。

算法设计1:加约束条件的枚举算法

最简单的算法就是通过八重循环模拟搜索空间中的88个状态,按深度优先思想,从第一个皇后从第一列开始搜索,每前进一步检查是否满足约束条件,不满足时,用continue语句回溯,满足满足约束条件,开始下一层循环,直到找出问题的解。

约束条件不在同一列的表达式为xi xj;而在同一主对角线上时xi-i=xj-j, 在同一负对角线上时xi+i=xj+j,因此,不在同一对角线上的约束条件表示为abs(xi-xj) abs(i-j)(abs()取绝对值)。

算法1:

queen1( )

{int a[9];

for (a[1]=1;a[1]<=8;a[1]++)

for (a[2]=1;a[2]<=8;a[2]++)

{if ( check(a,2)=0 ) continue;

for (a[3]=1;a[3]<=8;a[3]++)

{if(check(a,3)=0) continue;

for (a[4]=1;a[4]<=8;a[4]++)

{if (check(a,4)=0) continue;

for (a[5]=1;a[5]<=8;a[5]++)

{if (check(a,5)=0) continue;

for (a[6]=1;a[6]<=8;a[6]++)

{if (check(a,6)=0) continue;

for(a[7]=1;a[7]<=8;a[7]++)

{if (check(a,7)=0) continue;

for(a[8]=1;a[8]<=8;a[8]++)

{if (check(a,8)=0)

continue;

else

for(i=1;i<=8;i++)

print(a[i]);

}

} } } } } } }

check(int a[ ],int n)

{int i;

for(i=1;i<=n-1;i++)

if (abs(a[i]-a[n])=abs(i-n)) or (a[i]=a[n])

return(0);

return(1);

}

算法分析1:

若将算法中循环嵌套间的检查是否满足约束条件的:

“if  (check(a[],i)=0)continue;

i=2,3,4,5,6,7“

语句都去掉,只保留最后一个检查语句:

“if  (check(a[],8)=0)continue;”

相应地check()函数修改成:

check*(a[],n)

{int i,j;

for(i=2;i<=n;i++)

for(j=1;j<=i-1;j++)

if(abs(a[i]-a[j])=abs(i-j))or(a[i]=a[j])

return(0);

return(1);

}

则算法退化成完全的盲目搜索,复杂性就是88了

算法设计2:非递归回溯算法

以上的枚举算法可读性很好,但它只能解决八皇后问题,而不能解决任意的n皇后问题。下面的非递归算法可以说是典型的回溯算法模型。

算法2:

int a[20],n;

queen2( )

{

input(n);

backdate(n);

}

backdate (int n)

{ int k;

a[1]=0; k=1;

while( k>0 )

{a[k]=a[k]+1;

while ((a[k]<=n) and (check(k)=0)) /搜索第k个皇后位置/

a[k]=a[k]+1;

if( a[k]<=n)

if(k=n ) output(n); / 找到一组解/

else {k=k+1; 继续为第k+1个皇后找到位置/

a[k]=0;}/注意下一个皇后一定要从头开始搜索/

else k=k-1; /回溯/

}

}

check(int k)

{ int i;

for(i=1;i<=k-1;i++)

if (abs(a[i]-a[k])=abs(i-k)) or (a[i]=a[k])

return(0);

return(1);

}

output( )

{ int i;

for(i=1;i<=n;i++)

print(a[i]);

}

算法设计3:递归算法

这种方式也可以解决任意的n皇后问题。

这里我们用第三章3.2.3 “利用数组记录状态信息”的技巧,用三个数组c,b,d分别记录棋盘上的n个列、n个主对角线和n个负对角线的占用情况。

以四阶棋盘为例,如图5-13,共有2n-1=7个主对角线,对应地也有7个负对角线。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值