回溯法
目录
回溯法:抽象出来是深根遍历的方法,在递归构造中,生成和检查可以有机的结合起来,从而减小不必要的枚举。回溯法应用范围很广,只要能把带求解的问题分成不太多的步骤,每个步骤有只有不太多的选择,都可以考虑应用回溯法。
回溯法函数模板(自我总结):
void dfs(int cur){
if (cur==N){
//将当前所求解输出
tot++;//表示解的个数,初始化为0;
}
else
for(顺序查找可能的候选值){
if(满足条件){
C[cur]被赋值;
//vis[i]=1;已被访问
dfs(cur+1);
//vis[i]=0;还原未被访问状态
}
}
}
列举两个例子
1.求解八皇后问题
题目:棋盘上放置8个皇后,使得她们相互不攻击,此时每个皇后的攻击范围为同行同列同对角线,
要求找出所有的解。
解的表示输出N位整数(1,2,3,,N)的所有满足要求的排列;
void dfs(int cur){
int i,ok,j;
if(cur==N){
for(i=0;i<N;i++)
printf("%d ",C[i]);
printf("\n");
tot++;
}
else
for(i=1;i<=N;i++){
ok=1;
for(j=0;j<cur;j++){
if(C[j]==i||C[j]+j==i+cur||C[j]-j==i-cur){//不在同行同列同对角线
ok=0;break;
}
}
if(ok){
C[cur]=i;
dfs(cur+1);
}
}
}
2.回溯法求解素数环
题目:输入正整数n,把整数1,2,3,4,…,n组成一个环,使得相邻两个整数之间的和均为素数。
输出是从1开始逆时针输出,同一个环应恰好输出一次。n<=16;
该程序运行结果非常完美,当输入为16时,你会看到精彩的运行结果,何不试试呢?
(个人对此题有另外的理解:素数环有个特点,就是奇偶相间,
相邻的两个数必须一个是奇数另一个是偶数,输入的n必须是偶数,才能有解,否者无解。
各位大虾,能否按这个思路写出一个更加简洁的算法程序?)
实验测试用时,n=16,time=41s;
void dfs(int cur){
int i;
if(cur==n&&isp[C[cur-1]+C[0]])
{ for( i=0;i<n;i++){
printf("%d ",C[i]);
}
tot++;
printf("\n");
}
else for( i=2;i<=n;i++){
if(vis[i]==0&&isp[C[cur-1]+i]){
C[cur]=i;
vis[i]=1;
dfs(cur+1);
vis[i]=0;
}
}
}
运行截图
1.八皇后求解
2.素数环,n=6时,解
源代码
八皇后问题:
#include<stdio.h>
#include<stdlib.h>
#define N 8//N 表示皇后的个数
int C[N],tot=0;
void dfs(int cur){
int i,ok,j;
if(cur==N){
for(i=0;i<N;i++)
printf("%d ",C[i]);
printf("\n");
tot++;
}
else
for(i=1;i<=N;i++){
ok=1;
for(j=0;j<cur;j++){
if(C[j]==i||C[j]+j==i+cur||C[j]-j==i-cur){//不在同行同列同对角线
ok=0;break;
}
}
if(ok){
C[cur]=i;
dfs(cur+1);
}
}
}
int main(){
int cur=0;
dfs(cur);
printf("tot=%d\n",tot);
return 0;
}
素数环求解
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define N 20
int C[N],isp[2*N],vis[N];
int tot,n;
int isprime(int b){
int i;
if(b<=3)return 1;
for(i=2;i*i<=b;i++){
if(b%i==0)return 0;
}
return 1;
}
void dfs(int cur){
int i;
if(cur==n&&isp[C[cur-1]+C[0]])
{ for( i=0;i<n;i++){
printf("%d ",C[i]);
}
tot++;
printf("\n");
}
else for( i=2;i<=n;i++){
if(vis[i]==0&&isp[C[cur-1]+i]){
C[cur]=i;
vis[i]=1;
dfs(cur+1);
vis[i]=0;
}
}
}
int main(){
int i,cur;
memset(vis,0,sizeof(vis));//include<string.h>
scanf("%d",&n);
for(i=1;i<2*N;i++){
isp[i]=isprime(i);
}
tot=0;
cur=1;
C[0]=1;
dfs(cur);
printf("tot=%d",tot);
return 0;
}
以上是个人的学习心得,若有不当之处,还请多多指教。