回溯法(1)

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

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;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值