您的位置:首页 > 编程语言 > Java开发

回溯法(1)

2015-11-23 16:17 337 查看
回溯法(探索与回溯法)是一种选优搜索法,又称为试探法,按选优条件向前搜索,以达到目标。但当探索到某一步时,发现原先选择并不优或达不到目标,就退回一步重新选择,这种走不通就退回再走的技术为回溯法,而满足回溯条件的某个状态的点称为“回溯点”。

1.组合问题

从n个数(1,2…n)中选出r个数的组合(不重复).

组合数是不考虑顺序的,不妨设:

a[r]>a[r-1]>…a[1],

从这里可以看出a[r]>r-1。

算法:

1)取初始状态a[0]=n,i=0.

2)当a[0]>r-1时,重复操作:

如果a[i]>r-i-1:

1.i=r,a[i]=a[i]-1.

2.i!=r,i=i+1,a[i]=a[i-1]-1.

如果a[i]<=r-i-1:

i=i-1,a[i]=a[i]-1.(这一步是回溯)

3)结束.

public class Combination {

public static void main(String args[]){
int n=10,r=5;
int i=0,a[]=new int[r];
a[0]=n;
while(a[0]>r-1){
if(a[i]>r-i-1){
if(r==i+1){
output(a);
a[i]--;
}
else{
a[i+1]=a[i]-1;
i++;
}
}
else{
i--;
a[i]--;
}
}
}
private static void output(int[] a) {
// TODO Auto-generated method stub
for(int j=0;j<a.length;j++){
System.out.print(a[j]+"");
}
System.out.println();
}
}


2.数的划分

整数n分成k份,每份不能为空,任意两份不能相同(不考虑顺序)。

例如:n=7,k=3,下面三种分法认为是相同的。

1,1,5 1,5,1, 5,1,1

问有多少种不同的分法。

由于不考虑顺序,不妨让分法有递增顺序(即采取1,1,5的表示方法)。

算法:

1)初始状态a[0]=1,i=0,sum=n-1,nk=n/k,t=0

(数组a[k]代表不同分法表示的k个数,t是用来计数有多少种不同分法的,a[0]的值是不能超过nk的,sum表示还剩下多少可以划分,比如n=7,a[0]=1,a[1]=1,这个时候sum=5,因为还有5可以划分)

2)当a[0]<=nk时,重复操作:

如果i=k,则t=t+1,a[i]=sum+a[i],输出数组a,i=i-1,a[i]+1,sum=a[i+1]-1。(回溯)

如果i< k:

1.如果sum>=a[i]:i=i+1,a[i]=a[i-1]

2.如果sum< a[i]:i=i-1,a[i]=a[i]+1 (回溯)

3)输出t,结束。

public class NumberDivide {

public static void main(String args[]){
int n=10,k=5;
if(k>n){
System.out.println("none");
return;
}
int nk=n/k,t=0,i=0,sum=n-1;
int a[]=new int[k];
a[0]=1;
while(a[0]<=nk){
if(i==k-1){
a[i]=sum+a[i];
output(a);
i--;
a[i]++;
sum=a[i+1]-1;
t++;
}
else{
if(sum>=a[i]){
i++;
a[i]=a[i-1];
sum=sum-a[i];
}
else{
i--;
a[i]++;
sum=sum+a[i+1]-1;
}
}
}
System.out.println(t);
}

private static void output(int[] a) {
// TODO Auto-generated method stub
for(int j=0;j<a.length;j++){
System.out.print(a[j]+"");
}
System.out.println();
}
}


3.老鼠走迷宫

问题:有一个迷宫,在迷宫的某个出口放着一块奶酪。将一只老鼠由某个入口处放进去,它必须穿过迷宫,找到奶酪。请找出它的行走路径。

class Position{
int x,y;
public Position(int x,int y){
this.x=x;
this.y=y;
}
}
public class Maze {

static int size;
static int maze[][]=new int[size+2][size+2];

private static boolean findPath(){
ArrayStack path=new ArrayStack();

Position offset[]=new Position[4];
offset[0]=new Position(0,1);
offset[1]=new Position(1,0);
offset[2]=new Position(0,-1);
offset[3]=new Position(-1,0);

for(int i=0;i<=size+1;i++){
maze[0][i]=maze[size+1][i]=1;
maze[i][0]=maze[i][size+1]=1;
}
Position here=new Position(1,1);
maze[1][1]=1;
int option=0;
int lastOption=3;

while(here.x!=size||here.y!=size){
int r=0,c=0;
while(option<=lastOption){
r=here.x+offset[option].x;
c=here.y+offset[option].y;
if(maze[r][c]==0)
break;
option++;
}
if(option<=lastOption){
path.push(here);
here=new Position(r,c);
maze[r][c]=1;
option=0;
}
else{
if(path.isEmpty())return false;
Position next=(Position) path.pop();
if(next.x==here.x){
option=2+next.y-here.y;
}
else
option=3+next.x-here.x;
here=next;
}
}
return true;
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息