回溯枚举法

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

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

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

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

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

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

        针对所给问题,一般的解题步骤为:确定问题的解空间 --> 确定结点的扩展搜索规则--> 以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("\n");
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:\n",cnt);
61         mark[1] = 1;
62         DFS(1);
63         printf("\n");
64     }
65     return 0;
66 }


原文地址:https://www.cnblogs.com/yuxiaoba/p/8452794.html

时间: 2024-08-01 20:10:10

回溯枚举法的相关文章

八皇后问题(回溯法&amp;枚举法)

作者 : 卿笃军 本文讨论了八皇后问题的三种解决方案: 一.枚举法 二.回溯法(递归版) 三.回溯法(非递归版) 本来这些代码是以前编写好的,没有发表,由于最近又学习到了八皇后问题,自己整理了一下发表了出来! 首先.说明一下何为八皇后问题,我也不去谷歌了,直接简单的说明一下: 八皇后问题,就是在一个8*8的平面棋盘上,要求你摆放8个棋子,要求:这8个棋子不能有2个在同一行,也不能有2个在同一列,同时一条斜线上面也不能有2个~~~~ 比如:4*4的棋盘,你可以这样摆放(4皇后问题): 以上图为参照

枚举法判断某天是否为2015年节假日或周末

枚举法判断某天是否为2015年节假日或周末 1.节假日枚举类 /** *功能说明:节假日枚举类 * *创建人:Gansuper * *创建时间:2015-2-6 上午10:32:17 * *修改人 修改时间 修改描述 * */ public enum HolidayEnum { HOLIDAY(new String[]{"2015-01-01","2015-01-02","2015-01-03", "2015-02-18",&

Mobile Computing-天平难题-Uva1354(回溯枚举二叉树)

原题:https://uva.onlinejudge.org/external/13/1354.pdf 有s块石头,每块都被一根绳子吊着,如果有两个及以上的石头,需要平衡的天平把所有的石头挂起来. 房间的宽度为r,问小于房间宽度r的天平的最大宽度. 分析: 是个回溯枚举的问题,枚举中途如果发现当前宽度已经大于r,回溯. 难点: 也可以说是亮点,就是枚举所有的二叉树,一个天平可以看成是一个二叉树. 具体点说递归建立二叉树的过程就是每次从包含所有节点的集合中选择两个节点,合二为一 所以我们建树的过程

【算法学习笔记】28.枚举法 解题报告 SJTU_OJ 1255 1256 魔戒

1256. 你的魔戒?不,是你的魔戒.加强版 Description 在前往末日火山的途中,佛罗多与他的霍比特人同胞不幸被半兽人抓住了.半兽人要对每个霍比特人进行询问,以找出哪个霍比特人携带了至尊魔戒.每个霍比特人可能会说以下几种话: I have the ring. 我有魔戒. I have not the ring. 我没有魔戒. XXX has the ring. XXX有魔戒.(XXX表示某个霍比特人的名字) XXX has not the ring. XXX没有魔戒. Today is

枚举法的简单应用

箱子里有红,黄,蓝,白,黑五种颜色玻璃球若干,每次任意拿出三个球,问拿出三种不同颜色玻璃球的可能取法,请输出每种排列的情况. 注解:利用枚举法定义五种情况,“enum color {red,yellow,blue,white,black};”,定义四个整形变量“int i,j,k,m=0;”,依次从i到k分别进行从红到黑的情况循环,利用if来决断i,j,k互不相等的情况,针对每种情况通过调用函数来进行输出转换,得到结果. 编程: #include <iostream>using namespa

枚举法的应用

枚举法的应用——炸弹人小游戏 1 #include <iostream> 2 3 #define H 20 //地图行上限 4 #define L 21 //地图列上限 5 6 /* run this program using the console pauser or add your own getch, system("pause") or input loop */ 7 8 void BackUp(char map[][L],int n,int m,char ba

暴力枚举法总结

集训快要结束了,按照要求需要写一篇关于枚举的总结,于是在网上也看了许多其他菊苣写的文章,深受启发,但是思来想去感觉又不太系统,于是希望能在吸收那些知识后做一些整理,帮助后面的新人. 枚举的基本方法: 枚举,枚举,顾名思义,就是将所有情况都举出,并判断其是否符合题目条件.所以枚举的基本方法便是分析题意后,找到一个合适的维度列举每一个元素,以完成题目.其中如何找到一个合适的维度来进行枚举便是其中的最大难点. 枚举的基本条件: 首先是时间条件.一般来说主流的OJ当中,1000ms的时间限制下可以运行操

【算法学习笔记】64. 枚举法 SJTU OJ 1381 畅畅的牙签

枚举法就好了,推理很麻烦,感觉也做不出来. 创造一个结构体,一个是真实的数,一个是花费的牙签数. 构建一位数,两位数,三位数即可. #include <iostream> #include <vector> using namespace std; //从0到9耗费的牙签数 int cost[10]={6,2,5,5,4,5,6,3,7,6}; struct num { int n;//用于计算的数 int c;//耗费的牙签 }; num v[100000]; int main(

算法设计——枚举法

算法上机课,要我们用枚举法求解. 1. 由0到4五个数字,组成5位数,每个数字用一次,但十位和百位不能为3(当然万位不能为0),输出所有可能的五位数. 我用的是C语言,visualC++编写的 #include<stdio.h> int main() { int i,j,k,m,n; int count=0; for(i=1;i<=4;i++){ for(j=0;j<=4;j++){ if(j==i) continue; for(k=0;k<=4;k++){ if(k==3|