由素数环思考回溯算法的实现步骤

由素数环思考回溯算法的实现步骤

素数环题目代码解答:

/*
 * 素数环,相邻两个相加是否为素数,数字范围(1~20)
 * 数组+和是否素数
 * 回溯,返回到上一个
 */
public class PrimeRing {
    public static int NUMLENGTH=20;
    public static void main(String args[]){
        int [] arr=new int[NUMLENGTH];
        arr[0]=1;//第一个数字只能为1
        int k=1;
        while(k>=1){//极小边界限制
            arr[k]=arr[k]+1;
            while(arr[k]<NUMLENGTH){//极大边界限制
                if(check(arr, k)==1)
                    break;//符合条件,跳出循环
                else
                    arr[k]=arr[k]+1;//叠加到下一位
            }
            if(arr[k]<=NUMLENGTH&&k==NUMLENGTH-1){//求解完毕,输出解
                for(int x:arr)
                    System.out.print(x+" ");
                return ;
            }
            if(arr[k]<NUMLENGTH&&k<NUMLENGTH-1){//填写下一个位置
                k=k+1;
            }
            else{
                arr[k--]=0;//回溯
            }
        }
    }
    /**
     * 判断当前放进的数字是否符合条件
     * 1.是否与之前重复
     * 2.相邻之和是否素数
     * 3.第一个和最后一个相加是否为素数
     */
    public static int check(int[] arr,int k){
        int flag=0;
        for(int i=0;i<k;i++){//是否与之前重复
            if(arr[i]==arr[k])
                return 0;
        }
        flag=prime(arr[k-1]+arr[k]);//相邻之和是否素数
        if(flag==1&&k==NUMLENGTH-1){//k保证了为最后一个;第一个和最后一个相加是否为素数
            flag=prime(arr[0]+arr[k]);
        }
        return flag;

    }
    /*
     * 判断之和是否为素数
     */
    public static int prime(int sum){
        int n=(int)Math.sqrt(sum);
        for(int i=2;i<=n;i++){
            if(sum%i==0)
                return 0;
        }
        return 1;

    }
}

这道是典型的回溯问题,对于此问题,相应的算法是有规律可行的。在此我自己总结成伪代码,以后方可往里面套就可以解除问题的解了。

步骤如下:

void way{

  1. 初始化数组结构(已知和未知的量)
  2. while循环,条件k>=左边界 
    2-1. 赋值将要插入的判断值(总是从小到大)a[k]=a[k]+1; 
    2-2. while循环,条件arr[k]<=最大值{ 
    找出题目条件的一位,否则试下一个数字} 
    关键就是判断是否符合条件的函数 
    2-3. 得到解的其中一个条件可以为k==右边界-1,具体问题具体分析,要return; 
    2-4. if(arr[k]<=n&&k<右边界-1) 
    移动到下一位 k++; 
    else 
    回溯; 将这个将要填写的值赋值为0,移到上一位。a[k–]=0; 
    }

大题就是这个框架,而关键在于

  1. 判断是否符合条件,因题目的变化而变化,典型是要判断重复;
  2. 找到正解时,进行跳出
  3. 回溯;移动到上一位,难点在这里,很多题目并不是k–;就移动到上一步的步骤的,而更多的是用path数组来记录路径,通过path来回到上一步。

注意:每次使用while()循环,必须关注边界的处理跳出

下面看一道,要使用路径的回溯问题 
题目:

今有7对数字:两个1,两个2,两个3,…两个7,把它们排成一行。 
要求,两个1间有1个其它数字,两个2间有2个其它数字,以此类推,两个7之间有7个其它数字。如下就是一个符合要求的排列: 
17126425374635 
当然,如果把它倒过来,也是符合要求的。 
请你找出另一种符合要求的排列法,并且这个排列法是以74开头的。 
注意:只填写这个14位的整数,不能填写任何多余的内容,比如说明注释等。 
74*4*7****

代码参考:

package backalg;
/*
 * 今有7对数字:两个1,两个2,两个3,...两个7,把它们排成一行
 * 74****4*7*******
 * 0123456789
 *           1011121314
 */
public class NumSort {
    static int[] arr=new int[14];
    static int[] path=new int[14];
    public static void main(String[] args){

        arr[0]=7;
        arr[1]=4;
        arr[8]=7;
        arr[6]=4;
        int k=2;
        while(k>=2){
            arr[k]=arr[k]+1;//因为刚开始都是从0开始,所以往上增加,寻找合适的
            while(arr[k]<=6){
                if(check(k,arr[k])==1){
                    path[k]=1;//存储此路径
                    break;
                }
                else
                    arr[k]=arr[k]+1;
            }

            if(arr[k]<=6&&k<arr.length-1){//寻找下一个为0的值

                k++;
                while(k<arr.length&&arr[k]!=0){//找没有填入过的数字
                    k++;
                }
                if(k==arr.length){//知道长度一样的话, 说明已经填满了整一个数字
                    for(int x:arr)
                        System.out.print(x);
                    System.out.println();
                    return;
                }

            }else{
                arr[k--]=0;//将此要填的数字值为0,因为上面已经试过了,都不符合,自然值也变了,所以要重新置为0,并让k移动到上一位

                while(k>=2&&path[k]==0){//倒流找上一次填入数字的路径
                    k--;
                }
                path[k]=0;//重置

                if((arr[k]+k+1)<arr.length)//重新对上一次的进行判断,所以对应的要变为0
                    arr[arr[k]+k+1]=0;
            }
        }
    }
    /*
     * 判断是否重复
     * 对应赋值判断,是否符合条件
     */
    public static int check(int k,int value){
        for(int i=0;i<k;i++)//从左往右扫,判断是否有重复
            if(arr[i]==value)
                return 0;
        if(k+value+1<arr.length&&arr[k+value+1]==0)//判条件,中间要有几对
            arr[k+value+1]=value;
        else
            return 0;
        return 1;
    }

}

另一种解法的地址:数字排列

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值