5 回溯法.docx

上传人:b****6 文档编号:7957367 上传时间:2023-01-27 格式:DOCX 页数:66 大小:40.37KB
下载 相关 举报
5 回溯法.docx_第1页
第1页 / 共66页
5 回溯法.docx_第2页
第2页 / 共66页
5 回溯法.docx_第3页
第3页 / 共66页
5 回溯法.docx_第4页
第4页 / 共66页
5 回溯法.docx_第5页
第5页 / 共66页
点击查看更多>>
下载资源
资源描述

5 回溯法.docx

《5 回溯法.docx》由会员分享,可在线阅读,更多相关《5 回溯法.docx(66页珍藏版)》请在冰豆网上搜索。

5 回溯法.docx

5回溯法

5回溯法

回朔法即是:

若在当前位置探测到一条通路则继续向前,若在当前位置探测不到一条通路则回朔侄前一位置继续探测尚未探测的反向,直到找到一条通路或探测出无通路存在为止。

定义:

也叫试探法,它是一种系统地搜索问题的解的方法。

回溯算法的基本思想是:

从一条路往前走,能进则进,不能进则退回来,换一条路再试。

用回溯算法解决问题的一般步骤为:

  一、定义一个解空间,它包含问题的解。

  二、利用适于搜索的方法组织解空间。

  三、利用深度优先法搜索解空间。

  四、利用限界函数避免移动到不可能产生解的子空间。

问题的解空间通常是在搜索问题的解的过程中动态产生的,这是回溯算法的一个重要特性。

回溯法是一个既带有系统性又带有跳跃性的的搜索算法。

它在包含问题的所有解的解空间树中,按照深度优先的策略,从根结点出发搜索解空间树。

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

如果肯定不包含,则跳过对以该结点为根的子树的系统搜索,逐层向其祖先结点回溯。

否则,进入该子树,继续按深度优先的策略进行搜索。

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

而回溯法在用来求问题的任一解时,只要搜索到问题的一个解就可以结束。

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

例题:

1、排列的实现,对于n个不同数的排列并输出。

定义一个数组a[n],开始从第一个元素填入1开始,每进一步都是从1开始,并检查是否把n个元素填完和n个元素都没有重复的,如果是则输出一个解。

如果欲填入的数与之前已经填入的数重复,则增加1再比较,直到没有重复(除非已到了上限),如果已经到达了上限n,否回朔回上一个元素,值到其值不为上限n,然后上一个元素,下一个元素从1重新开始。

C++程序1

#include

voidmain()

{

intn,m,i=0,j=0,k=0,flag=0,f=0;

staticinta[40];

printf("输入N:

");

scanf("%d",&n);

a[1]=1;

k=1;

while

(1)

{

flag=1;

for(i=1;i

if(a[k]==a[i])

{

flag=0;

break;

}

if(flag&&k==n)

{

for(j=1;j<=n;j++)

printf("%d",a[j]);

printf("\n");

}

if(k

k++;

a[k]=1;

continue;

}

while(a[k]==n&&k>1){k--;}

if(a[k]==n&&k==1)

break;

else

{

a[k]++;

}

}

}

C++程序2、排列的算法差不多,为了不重复,加了一个条件,也就是递增数列

#include

voidmain()

{

intn,m,i=0,j=0,k=0,flag=0,f=0;

staticinta[40];

printf("输入N,M:

");

scanf("%d%d",&n,&m);

a[1]=1;

k=1;

while

(1)

{

flag=1;

for(i=1;i

if(a[k]==a[i]||a[k]

{

flag=0;

break;

}

if(flag&&k==m)

{

for(j=1;j<=m;j++)

printf("%d",a[j]);

printf("\n");

}

if(k

{

k++;

a[k]=1;

continue;

}

while(a[k]==n&&k>1){k--;}

if(a[k]==n&&k==1)

break;

else

{

a[k]++;

}

}

}

C++程序3

#include

#include

voidmain(){

intn,i=1;

printf("请输入N值=?

");

scanf("%d",&n);

inta[30]={0};//C语言中完成数组定义并初始化不能用变量N,只能用具体数字,这儿采用比较大的30

a[1]=1;

while(i<=n)

{

if(i==n){

for(intj=1;j

printf("%d\n",a[n]);//输出一组解

}

if(i

while(a[i]==n&&i>1)i--;//向前回溯

if(a[i]==n&&i==1)break;//结束

elsea[i]=a[i]+1;

}

}

JAVA程序

用回溯法求任意1到N个数字的全排列。

自动生成a[i]值(1到N间各1个数字),再全排列,如同N重循环中各下标的变化。

(类似于多重循环的穷举法,比多重循环的穷举法慢。

但程序有较通用的特性。

importjava.lang.Math;

importjava.util.*;

publicclassaa1

{

publicstaticvoidmain(String[]args)

{

System.out.println("请输入位数");

Scannerscan1=newScanner(System.in);

intn=scan1.nextInt();

inti=1;

inta[]=newint[n+1];

a[1]=1;

while(i<=n)

{

if(i==n){

for(intj=1;j

System.out.println(a[n]);

}

if(i

while(a[i]==n&&i>1)i--;//向前回溯

if(a[i]==n&&i==1)break;//程序运行全部结束

elsea[i]=a[i]+1;//向前回溯,前一位数字加1

}

}

}

2、求解21位水仙花数

程序1:

(用时6300毫秒)

importjava.math.BigInteger;

importjava.util.Arrays;

importjava.util.HashSet;

importjava.util.Hashtable;

publicclassTest{

publicstaticvoidmain(String[]args){

longxxx=System.currentTimeMillis();//记录开始进入时的时间

Testtest=newTest(21);//修改本数字可以求任何一位水仙花数

HashSetset=newHashSet();

ints=test.MAX.divide(test.p(9)).intValue();

//System.out.println("s="+s);

for(inti=0;i<=s;i++){

BigIntegertemp=test.solve(i);

if(temp!

=null)set.add(temp);//加入一个满足要求的解

}

BigInteger[]result=newBigInteger[set.size()];

//System.out.println("result="+result);

set.toArray(result);

Arrays.sort(result);

for(BigIntegerbi:

result){

System.out.println("bi="+bi);

}

xxx=System.currentTimeMillis()-xxx;//记录退出时的时间

System.out.println("用时:

"+xxx+"毫秒");//显示程序运行时间

}

publicTest(intsize){

this.size=size;

ints=size<10?

10:

size;

for(inti=0;i<=s;i++){

ht.put("n_"+i,newBigInteger(String.valueOf(i)));

}

for(inti=0;i<=10;i++){

ht.put("p_"+i,newBigInteger(String.valueOf(i)).pow(size));

}

MIN=n(10).pow(size-1);

MAX=n(10).pow(size).subtract(n

(1));

}

privateintsize;

privateint[]array=newint[10];

privateint[]sumArray=newint[10];

privateBigInteger[]totalSum=newBigInteger[10];

privateintindex=0;

privateBigIntegerZERO=BigInteger.ZERO;

privateBigIntegerMIN;

privateBigIntegerMAX;

privateHashtableht=newHashtable();

privateBigIntegern(inti){

//System.out.println("n_+i="+i);

returnht.get("n_"+i);

}

privateBigIntegerp(inti){

//System.out.println("p_+i="+i);

returnht.get("p_"+i);

}

privatebooleancheckPersentArray(){

BigIntegerminVal=totalSum[index];

BigIntegermaxVal=totalSum[index].add(p(9-index).multiply(

n(size-sumArray[index])));

if(minVpareTo(MAX)>0){

returnfalse;

}

if(maxVpareTo(MIN)<0){

returnfalse;

}

StringminStr=minVpareTo(MIN)>0?

minVal.toString():

MIN

.toString();

StringmaxStr=maxVpareTo(MAX)<0?

maxVal.toString():

MAX

.toString();

int[]sameCountArray=newint[10];

for(inti=0;i

charc;

if((c=minStr.charAt(i))==maxStr.charAt(i)){

sameCountArray[c-'0']=sameCountArray[c-'0']+1;

}else{

break;

}

}

for(inti=0;i<=index;i++){

if(array[i]

returnfalse;

}

}

if(sumArray[index]==size){

StringsumStr=totalSum[index].toString();

BigIntegersum=ZERO;

for(inti=0;i

sum=sum.add(p(sumStr.charAt(i)-'0'));

}

returnpareTo(totalSum[index])==0;

}

returntrue;

}

privatevoidsetValue(intnum){

array[index]=num;

if(index==0){

sumArray[index]=num;

totalSum[index]=p(9-index).multiply(n(num));

//System.out.println("n(num)totalSum[index]="+totalSum[index]+"index="+index);

//try{Thread.sleep(1000);}catch(InterruptedExceptionex){}//暂停6秒

}else{

sumArray[index]=sumArray[index-1]+num;

totalSum[index]=totalSum[index-1].add(p(9-index).multiply(n(num)));

//System.out.println("elsetotalSum[index]="+totalSum[index]);

//try{Thread.sleep(1000);}catch(InterruptedExceptionex){}//暂停6秒

}

}

privatebooleanback(){

if(array[index]==0){

while(array[index]==0){

if(index>0){

index--;

}else{

returntrue;

}

}

}

if(index>0){

setValue(array[index]-1);

returnfalse;

}else{

//System.out.println("elsefalse="+false);

//try{Thread.sleep(1000);}catch(InterruptedExceptionex){}//暂停3秒

returntrue;

}

}

privateBigIntegersolve(intstartValue){

index=0;

setValue(startValue);

while(true){

if(checkPersentArray()){

if(sumArray[index]==size){//如果数组之和针对全数组,满足条件,返回一个解

returntotalSum[index];

}

if(index!

=9){

index++;

setValue(size-sumArray[index-1]);

continue;

}

}

if(back()){

break;

}

}

returnnull;

}

}

程序2:

(用时9828毫秒)穷举法

importjava.lang.System;

importjava.util.*;

importjava.io.*;

importjava.lang.Math;

publicclassaa18{

staticinta[]={0,1,2097152,353203,6511104,8203125,377856,3284007,4775808,2359209};

staticintb[]={0,0,0,1046,439804,7683715,3695064,4586408,7203685,8913151};

staticintc[]={0,0,0,0,0,4,219,5585,92233,1094189};

staticintd[]={0,0,0};

staticintg[]=newint[10];

//staticinti=0,j=0,k=0,sum=0;

staticintx=0,y=0,z=0;

staticintx1=0,y1=0,z1=0;

publicstaticvoidmain(String[]args){

longxxx=System.currentTimeMillis();//记录开始进入时的时间

//以下i0表示0的个数,最多20个0,i1表示1的个数,最多21个1等

for(inti0=0;i0<=20;i0++){

for(inti1=0;i1<=21;i1++){if(i0+i1>21)continue;

for(inti2=0;i2<=21;i2++){if(i0+i1+i2>21)continue;

for(inti3=0;i3<=21;i3++){if(i0+i1+i2+i3>21)continue;

//如果数字的个数超过21或不到20个,退出本循环continue

for(inti4=0;i4<=21;i4++){if(i0+i1+i2+i3+i4>21)continue;

for(inti5=0;i5<=21;i5++){if(i0+i1+i2+i3+i4+i5>21)continue;

for(inti6=0;i6<=21;i6++){if(i0+i1+i2+i3+i4+i5+i6>21)continue;

for(inti7=0;i7<=21;i7++){if(i0+i1+i2+i3+i4+i5+i6+i7>21)continue;

for(inti8=0;i8<=21;i8++){if(i0+i1+i2+i3+i4+i5+i6+i7+i8>21)continue;

for(inti9=0;i9<=20;i9++){if(i0+i1+i2+i3+i4+i5+i6+i7+i8+i9!

=21)continue;

//以下求每个数字的21次方之和

//System.out.println(i0+""+i1+""+i2+""+i3+""+i4+""+i5+""+i6+""+i7+""+i8+""+i9);

d[0]=a[1]*i1+a[2]*i2+a[3]*i3+a[4]*i4+a[5]*i5+a[6]*i6+a[7]*i7+a[8]*i8+a[9]*i9;//低7位之和

//System.out.println("d[0]="+d[0]);

d[1]=d[0]/10000000;//向中7位的进位

d[0]=d[0]%10000000;

d[1]=d[1]+b[3]*i3+b[4]*i4+b[5]*i5+b[6]*i6+b[7]*i7+b[8]*i8+b[9]*i9;//中7位之和

//System.out.println("d[1]="+d[1]);

d[2]=d[1]/10000000;//向高7位的进位

d[1]=d[1]%10000000;

d[2]=d[2]+c[5]*i5+c[6]*i6+c[7]*i7+c[8]*i8+c[9]*i9;//高位之和

x1=d[0];

y1=d[1];

z1=d[2];

//System.out.println("d[2]="+d[2]);

if(d[2]/10000000>0)break;//如果高位多于7位,该数超过21位,不符要求,退出

for(intj=0;j<10;j++)g[j]=0;//准备计数字的个数

//System.out.println(d[2]+""+d[1]+""+d[0]);

for(intk1=0;k1<3;k1++){

for(intk=6;k>=0;k--){

y=1;

for(intk0=1;k0<=k;k0++)y=y*10;

x=d[k1]/y;//取高位的一个数字

//System.out.print("d[k1]="+d[k1]+"y="+y+"x="+x);

d[k1]=d[k1]%y;//取高位的一个数字后余数

//System.out.println("d[k1]="+d[k1]);

g[x]=g[x]+1;//计数字x出现的次数

//System.out.println(x+"g["+x+"]="+g[x]);

}}

//System.out.println(g[0]+""+g[1]+""+g[2]+""+g[3]+""+g[4]+""+g[5]+""+g[6]+""+g[7]+""+g[8]+""+g[9]);

//System.out.println(i0+""+i1+""+i2+""+i3+""+i4+""+i5+""+i6+""+i7+""+i8+""+i9);

if((g[0]==i0)&&(i0<10)&&(g[1]==i1)&&(g[2]==i2)&&(g[3]==i3)&&(g[4]==i4)&&(g[5]==i5)&&(g[6]==i6)&&(g[7]==i7)&&(g[8]==i8)&&(g[9]==i9))

System.out.println("解:

"+z1+""+y1+""+x1);

}

}

}

}

}

}

}

}

}

}

xxx=System.currentTimeMillis()-xxx;//记录退出时的时间

System.out.println("用时:

"+xxx+"毫秒");//显示程序运行时间

}

}

程序3:

本程序运行时间9秒,启动多个线程计算。

importjava.math.BigInteger;

importjava.util.Hashtable;

p

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 解决方案 > 学习计划

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1