zoukankan      html  css  js  c++  java
  • 回溯枚举法

             回溯法也称试探法,它可以系统的搜索一个问题的所有解或者任意解。

             回溯法是一个既带有系统性又带有跳跃性的的搜索算法。它在包含问题的所有解的解空间树中,按照深度优先的策略,从根结点

    出发搜索解空间树。算法搜索至解空间树的任一结点时,总是先判断该结点是否肯定不包含问题的解。如果肯定不包含,则跳过

    对以该结点为根的子树的系统搜索,逐层向其祖先结点回溯。否则,进入该子树,继续按深度优先的策略进行搜索。回溯法在用来

    求问题的所有解时,要回溯到根,且根结点的所有子树都已被搜索遍才结束。而回溯法在用来求问题的任一解时,只要搜索到问题

    的一个解就可以结束。这种以深度优先的方式系统地搜索问题的解的算法称为回溯法,它适用于解一些组合数较大的问题.

            针对所给问题,一般的解题步骤为:确定问题的解空间 --> 确定结点的扩展搜索规则--> 以DFS方式搜索解空间,并在搜索过程中用剪枝函数避免无效搜索。

    Prime ring problem

    题目描述

    A ring is compose of n circles as shown in diagram. Put natural number 1, 2, ..., n into each circle separately, and the sum of numbers in two adjacent circles should be a prime. 

    Note: the number of first circle should always be 1. 

     

    输入描述:

    n (0 < n < 20).
           

    输出描述:

    The output format is shown as sample below. Each row represents a series of circle numbers in the ring beginning from 1 clockwisely and anticlockwisely. The order of numbers must satisfy the above requirements. Print solutions in lexicographical order.
           

    You are to write a program that completes above process.

    Print a blank line after each case.
    示例1

    输入

    6
    8

    输出

    Case 1:
    1 4 3 2 5 6
    1 6 5 2 3 4
    
    Case 2:
    1 2 3 8 5 6 7 4
    1 2 5 8 3 4 7 6
    1 4 7 6 5 8 3 2
    1 6 7 4 3 8 5 2

    这道题是素数环问题,大意是由给定的1到n数字中,将数字依次填入环中,使得环中任意两个相邻的数字间的和为素数。
    对于给定的n,按字典序由小到大输出所有符合条件的解(第一个数恒定为1)
    在这里可以采用回溯法枚举每一个值。当第一个数位为1确定时,尝试放入第二个数,使其与1的和为素数,放入后再尝试
    放入第三个数,使其与第二个数的和为素数,直到所有的数全部放入环中,且最后一个数与1的和也是素数,则得到答案,输出。
    若在尝试放数的过程中,发现当前位置无论放置任何之前未被使用的数均不可能满足条件,那么回溯改变其上一个数,直到产生
    所需要的答案或不存在更多的解。
     1 #include<stdio.h>
     2 #include<stdlib.h>
     3 
     4 int ans[22];   //保存环中被放入的数
     5 int mark[22];  //标记之前被放入环中的数
     6 int n;
     7 int prime[]={2,3,5,7,11,13,17,19,23,29,31,37};//40内得素数,用于判断是否是素数
     8 
     9 int Judge( int x)
    10 {
    11     //判断一个数是否是素数
    12     int i;
    13     for( i=0; i<12; i++){
    14         if( prime[i]==x) return 1;
    15     }
    16     return 0;
    17 }
    18 
    19 void Check()
    20 {
    21     //检查输出由回溯法枚举得到的解
    22     int i;
    23     if( Judge(ans[n]+ans[1])==0) return;//判断最后一个数与第一个数的和是否是素数
    24     for( i=1; i<=n; i++){
    25         if( i!=1) printf(" ");
    26         printf("%d",ans[i]);
    27     }
    28     printf("
    ");
    29 }
    30 
    31 void DFS( int num)
    32 {
    33     //递归枚举,num为当前已经放入环中的数字
    34     int i;
    35     if( num>1 ) if( Judge(ans[num]+ans[num-1])==0 ) return;
    36 
    37     if( num==n ){
    38         //若已经放入n个数
    39         Check();
    40         return;
    41     }
    42     for( i=2; i<=n; i++){
    43         if(mark[i]==0){
    44             mark[i]=1;  //标记i为已经使用
    45             ans[num+1] = i;  //将这个数字放入ans数组中
    46             DFS( num+1 );
    47             mark[i] = 0; //重新标记为未使用
    48         }
    49     }
    50 }
    51 
    52 int main()
    53 {
    54     int cnt=0;  //记录case数
    55     int i;
    56     while( scanf("%d",&n)!=EOF){
    57         cnt++;
    58         for( i=0; i<22; i++) mark[i] = 0;  //初始化
    59         ans[1] = 1;
    60         printf("Case %d:
    ",cnt);
    61         mark[1] = 1;
    62         DFS(1);
    63         printf("
    ");
    64     }
    65     return 0;
    66 }
    
    
    在这个国度中,必须不停地奔跑,才能使你保持在原地。如果想要寻求突破,就要以两倍现在速度奔跑!
  • 相关阅读:
    VirtualBox设置共享文件夹失败的解决方法
    内存泄漏
    javascript语言精粹学习记录一
    javascript之继承
    HadoopFSDataset
    linux eclipse启动问题及解决方法
    css规范总结
    pycharm
    第十章 call和ret指令
    第五章 [bx]和loop指令
  • 原文地址:https://www.cnblogs.com/yuxiaoba/p/8452794.html
Copyright © 2011-2022 走看看