杭电ACM OJ 1016 Prime Ring Problem 回溯法+ 高效判断素数 快速轻松解决

来源:互联网 发布:seo搜索排名优化怎么 编辑:程序博客网 时间:2024/05/17 05:07

简单易理解的回溯法,高效判断素数,可以看我另外两篇博客,这里我也快速简要讲一下。


这一题主要是要领悟回溯法,很关键。

先写一个正常的n个数的求各种排列情况。就1到。。n。的各种排列情况。

方法:正常思路是第一个位置有n种情况,你要写一个长度n的for循环,第二个位置自然是n-1种情况,所以要写一个长度n的for循环,以此类推。。。但是问题来了,你怎么知道传进来的n是多少?你又要写几个for循环?所以你需要用回溯法来递归处理这个情况(当然也有不用递归的方法)。你需要写这样一个方法:你需要写一个标记数组,用来标记这个数字是否访问过了。还有一个标记当前正在处理哪个位数的level,如果level是0,那就是正在为第一位找,所以说不管从哪个位置开始找,方法都是一样的,唯一不同的是你正在为哪一位找以及有哪些数组已经用过了。

上代码

private void sort(int level) {    for (int i = 0; i < n; i ++) {        if (!flag[i]) {            current[level] = i + 1;            flag[i] = true;//比如倒数第二层:锁一个            if (level != n - 1) {                sort(level + 1);//留一个给最后一层            } else {                System.out.println(Arrays.toString(current));            }            flag[i] = false;//最后一层搞完后,恢复这一层,让剩下那个数再搞        }    }}
当你在最后一层的时候,就只能找到一个数了,就返回上一个循环,上一个循环可以找到两个数,第一个数已经找到符合的情况了,再用第二个数。再上一层也是一,以此类推。那么我们是怎么样实现这个回溯的功能的呢?其实for循环和递归写在那里了,他本身就可以回溯回去。我们唯一要做的就是,开始进入下一个循环之前,把当前的数标记为已经访问,完全退出下一个循环后,再把当前的数标记为未访问状态,当前的循环再去找下一个数。

讲的有点长,还是得去看看我原来的文章,讲的又简单又清楚。

[1, 2, 3, 4]
[1, 2, 4, 3]
[1, 3, 2, 4]
[1, 3, 4, 2]
[1, 4, 2, 3]
[1, 4, 3, 2]
[2, 1, 3, 4]
[2, 1, 4, 3]
[2, 3, 1, 4]
[2, 3, 4, 1]
[2, 4, 1, 3]
[2, 4, 3, 1]

。。。

可以看到已经成功输出了,搞定了回溯法后就可以轻松解决这个问题了,只需要在代码里改动小小的地方即可。

针对这题,就是:1.修改一下一个if语句,

if (!flag[i] && isPrime(current[level - 1] + i + 1)) {
与上一个数之和为素数

2.1不用放入回溯法内


public class PrimeRingProblem1016 {    private int n;    private int[] current;    private boolean[] flag;    PrimeRingProblem1016(int n) {        this.n = n;        current = new int[n];        flag = new boolean[n];        current[0] = 1;    }    //高效判断素数    private boolean isPrime(int num) {        if (num == 2 || num == 3) {            return true;        }        //如果不在6的倍数附近,肯定不是素数        if (num % 6 != 1 && num % 6 != 5) {            return false;        }        //6倍数附近的数进行判断        //这里添加了一个num % (i + 2) == 0,为什么?        //枚举一下i,i+2可能的取值,因为i +=6        //所以是这样的 5 7,11 13,17 19        //为什么呢?举一个35=36-1)的情况,是57的倍数        //再举一个 49=48+1),是7的倍数        //所以知道了,6附近的两个数不一定是质数,有可能是57的倍数        for (int i = 5; i <= Math.sqrt(num); i += 6) {            if (num % i == 0 || num % (i + 2) == 0) {                return false;            }        }        return true;    }    private void sort(int level) {        for (int i = 1; i < n; i++) {            if (!flag[i] && isPrime(current[level - 1] + i + 1)) {                current[level] = i + 1;                flag[i] = true;                if (level != n - 1) {                    sort(level + 1);                } else {                    System.out.println(Arrays.toString(current));                }                flag[i] = false;            }        }    }    public static void main(final String[] args) throws Exception {        PrimeRingProblem1016 primeRingProblem1016 = new PrimeRingProblem1016(6);        primeRingProblem1016.sort(1);    }}
我好想忘了1和最后一个数判断了,不过,没关系吧。。。

原创粉丝点击