1、5 回溯法5 回溯法回朔法即是:若在当前位置探测到一条通路则继续向前,若在当前位置探测不到一条通路则回朔侄前一位置继续探测尚未探测的反向,直到找到一条通路或探测出无通路存在为止。 定义: 也叫试探法,它是一种系统地搜索问题的解的方法。回溯算法的基本思想是: 从一条路往前走,能进则进, 不能进则退回来,换一条路再试。用回溯算法解决问题的一般步骤为:一、定义一个解空间,它包含问题的解。二、利用适于搜索的方法组织解空间。三、利用深度优先法搜索解空间。四、利用限界函数避免移动到不可能产生解的子空间。 问题的解空间通常是在搜索问题的解的过程中动态产生的,这是回溯算法的一个重要特性。回溯法是一个既带有系统
2、性又带有跳跃性的的搜索算法。它在包含问题的所有解的解空间树中,按照深度优先的策略,从根结点出发搜索解空间树。算法搜索至解空间树的任一结点时,总是先判断该结点是否肯定不包含问题的解。如果肯定不包含,则跳过对以该结点为根的子树的系统搜索,逐层向其祖先结点回溯。否则,进入该子树,继续按深度优先的策略进行搜索。 回溯法在用来求问题的所有解时,要回溯到根,且根结点的所有子树都已被搜索遍才结束。 而回溯法在用来求问题的任一解时,只要搜索到问题的一个解就可以结束。这种以深度优先的方式系统地搜索问题的解的算法称为回溯法,它适用于解一些组合数较大的问题。例题:1、排列的实现,对于n个不同数的排列并输出。定义一个
3、数组an,开始从第一个元素填入1开始,每进一步都是从1开始,并检查是否把n个元素填完和n个元素都没有重复的,如果是则输出一个解。如果欲填入的数与之前已经填入的数重复,则增加1再比较,直到没有重复(除非已到了上限),如果已经到达了上限n,否回朔回上一个元素,值到其值不为上限n,然后上一个元素,下一个元素从1重新开始。C+程序1#includevoid main() int n,m,i=0,j=0,k=0,flag=0,f=0; static int a40; printf(输入N:); scanf(%d,&n); a1=1; k=1; while(1) flag=1; for(i=1;ik;i+
4、) if(ak=ai) flag=0; break; if(flag&k=n) for(j=1;j=n;j+) printf(%d,aj); printf(n); if(k1)k-; if(ak=n&k=1) break; else ak+; C+程序2、排列的算法差不多,为了不重复,加了一个条件,也就是递增数列#includevoid main() int n,m,i=0,j=0,k=0,flag=0,f=0; static int a40; printf(输入N,M:); scanf(%d%d,&n,&m); a1=1; k=1; while(1) flag=1; for(i=1;ik;i
5、+) if(ak=ai|akai)/akai条件为了限制递增 flag=0; break; if(flag&k=m) for(j=1;j=m;j+) printf(%d,aj); printf(n); if(k1)k-; if(ak=n&k=1) break; else ak+; C+程序3#include #include void main() int n,i=1; printf(请输入N值=? ); scanf(%d,&n); int a30=0; /C语言中完成数组定义并初始化不能用变量N,只能用具体数字,这儿采用比较大的30 a1=1; while(i=n) if (i=n) for
6、 (int j=1;jn;j+) printf(%d ,aj); printf(%dn,an); /输出一组解 if (i1) i-; /向前回溯 if (ai=n & i=1) break; /结束 else ai=ai+1; JAVA程序用回溯法求任意1到N个数字的全排列。自动生成ai值(1到N 间各1个数字),再全排列,如同N重循环中各下标的变化。(类似于多重循环的穷举法,比多重循环的穷举法慢。但程序有较通用的特性。)import java.lang.Math;import java.util.*;public class aa1 public static void main(Stri
7、ng args) System.out.println(请输入位数); Scanner scan1 = new Scanner(System.in); int n = scan1.nextInt(); int i=1; int a=new intn+1; a1=1; while(i=n) if (i=n) for (int j=1;jn;j+) System.out.print(aj); /输出一组解 System.out.println(an); if (i1) i-; /向前回溯 if (ai=n & i=1) break; /程序运行全部结束 else ai=ai+1; /向前回溯,前一
8、位数字加1 2、求解21位水仙花数程序1:(用时6300毫秒)import java.math.BigInteger;import java.util.Arrays;import java.util.HashSet;import java.util.Hashtable;public class Test public static void main(String args) long xxx=System.currentTimeMillis(); /记录开始进入时的时间 Test test = new Test(21); /修改本数字可以求任何一位水仙花数 HashSet set = new
9、 HashSet(); int s = test.MAX.divide(test.p(9).intValue();/System.out.println(s=+ s); for (int i = 0; i = s; i+) BigInteger temp = test.solve(i); if(temp != null) set.add(temp); /加入一个满足要求的解 BigInteger result = new BigIntegerset.size();/System.out.println(result=+ result); set.toArray(result); Arrays.
10、sort(result); for(BigInteger bi : result) System.out.println(bi=+ bi); xxx=System.currentTimeMillis()-xxx; /记录退出时的时间 System.out.println(用时:+xxx+毫秒); /显示程序运行时间 public Test(int size) this.size = size; int s = size 10 ? 10 : size; for (int i = 0; i = s; i+) ht.put(n_ + i, new BigInteger(String.valueOf(
11、i); for (int i = 0; i = 10; i+) ht.put(p_ + i, new BigInteger(String.valueOf(i).pow(size); MIN = n(10).pow(size - 1); MAX = n(10).pow(size).subtract(n(1); private int size; private int array = new int10; private int sumArray = new int10; private BigInteger totalSum = new BigInteger10; private int in
12、dex = 0; private BigInteger ZERO = BigInteger.ZERO; private BigInteger MIN ; private BigInteger MAX; private Hashtable ht = new Hashtable(); private BigInteger n(int i) /System.out.println(n_ + i= +i); return ht.get(n_ + i); private BigInteger p(int i) /System.out.println(p_ + i= +i); return ht.get(
13、p_ + i); private boolean checkPersentArray() BigInteger minVal = totalSumindex; BigInteger maxVal = totalSumindex.add(p(9 - index).multiply( n(size - sumArrayindex); if (minVpareTo(MAX) 0) return false; if (maxVpareTo(MIN) 0 ? minVal.toString() : MIN .toString(); String maxStr = maxVpareTo(MAX) 0 ?
14、maxVal.toString() : MAX .toString(); int sameCountArray = new int10; for (int i = 0; i size; i+) char c; if (c = minStr.charAt(i) = maxStr.charAt(i) sameCountArrayc - 0 = sameCountArrayc - 0 + 1; else break; for (int i = 0; i = index; i+) if (arrayi sameCountArray9 - i) return false; if (sumArrayind
15、ex = size) String sumStr = totalSumindex.toString(); BigInteger sum = ZERO; for (int i = 0; i 0) index-; else return true; if (index 0) setValue(arrayindex - 1); return false; else /System.out.println(else false=+false); /try Thread.sleep(1000); catch(InterruptedException ex) /暂停3秒 return true; priv
16、ate BigInteger solve(int startValue) index = 0; setValue(startValue); while (true) if (checkPersentArray() if (sumArrayindex = size) /如果数组之和针对全数组,满足条件,返回一个解 return totalSumindex; if (index != 9) index+; setValue(size - sumArrayindex - 1); continue; if (back() break; return null; 程序2:(用时9828毫秒)穷举法imp
17、ort java.lang.System; import java.util.*;import java.io.*;import java.lang.Math;public class aa18 static int a=0,1,2097152,353203,6511104,8203125,377856,3284007,4775808,2359209; static int b=0,0,0,1046,439804,7683715,3695064,4586408,7203685,8913151; static int c=0,0,0,0,0,4,219,5585,92233,1094189; s
18、tatic int d=0,0,0; static int g=new int10;/ static int i=0,j=0,k=0,sum=0; static int x=0,y=0,z=0; static int x1=0,y1=0,z1=0; public static void main(String args) long xxx=System.currentTimeMillis(); /记录开始进入时的时间 /以下i0表示0的个数,最多20个0,i1表示1的个数,最多21个1等 for (int i0=0;i0=20;i0+) for (int i1=0;i121) continue
19、; for (int i2=0;i221) continue; for (int i3=0;i321) continue; /如果数字的个数超过21或不到20个,退出本循环 continue for (int i4=0;i421) continue; for (int i5=0;i521) continue; for (int i6=0;i621) continue; for (int i7=0;i721) continue; for (int i8=0;i821) continue; for (int i9=0;i90) break; /如果高位多于7位,该数超过21位,不符要求,退出 fo
20、r (int j=0;j10;j+) gj=0; /准备计数字的个数/System.out.println(d2+ +d1+ +d0); for (int k1=0;k1=0;k-) y=1; for (int k0=1;k0=k;k0+) y=y*10 ; x=dk1/y; /取高位的一个数字/System.out.print(dk1=+dk1+ y=+y+ x=+x); dk1=dk1%y; /取高位的一个数字后余数/System.out.println( dk1=+dk1); gx=gx+1; /计数字x出现的次数/System.out.println(x+g+x+=+gx); /Sys
21、tem.out.println(g0+ +g1+ +g2+ +g3+ +g4+ +g5+ +g6+ +g7+ +g8+ +g9);/System.out.println(i0+ +i1+ +i2+ +i3+ +i4+ +i5+ +i6+ +i7+ +i8+ +i9); if (g0=i0) & (i010) & (g1=i1) & (g2=i2) & (g3=i3) & (g4=i4) & (g5=i5) & (g6=i6) & (g7=i7) & (g8=i8) & (g9=i9) ) System.out.println(解:+z1+y1+x1); xxx=System.currentTimeMillis()-xxx; /记录退出时的时间 System.out.println(用时:+xxx+毫秒); /显示程序运行时间程序3:本程序运行时间9秒,启动多个线程计算。import java.math.BigInteger; import java.util.Hashtable; p
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1