学习算法,编程之路

回溯法

目录

回溯法:抽象出来是深根遍历的方法,在递归构造中,生成和检查可以有机的结合起来,从而减小不必要的枚举。回溯法应用范围很广,只要能把带求解的问题分成不太多的步骤,每个步骤有只有不太多的选择,都可以考虑应用回溯法。

回溯法函数模板(自我总结):

      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;
}

以上是个人的学习心得,若有不当之处,还请多多指教。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值