素数环dfs回溯算法的一点优化

描述

 有一个整数n,把从1到n的数字无重复的排列成环,且使每相邻的两个数(包括首和尾)的和都为素数,称为素数环。为了简便起见,我们规定每个素数环都从1开始。例如,6的一个素数环:
 1 4 3 2 5 6
 请编写一个程序,给定一个输入n(0<n<20),如果存在满足要求的素数环,从小到大输出。否则,输出No Answer。

  这道题我采用的是dfs加上回溯法来做的,回溯过程也很简单,其他博客里面肯定也会讲到,只是在dfs过程中有一个trick我觉得很不错,分享于此:
  首先全局定义一个数组

int Next_prime[1001];//Next_prime[i]表示大于i的最小的质数

  然后main函数中对其初始化

    {
        int j = 1;
        int pri = prime[j];// prime[i]代表第i个质数
        for(int i = 1; i < 501; i++)
        {
            if(i >= pri)
            {
                j ++;
                pri = prime[j];
            }
            Next_prime[i] = pri;
        }
    }

  然后在dfs中不是在最后位置的时候

    {
        int prenum = round[po - 1];/*round[i]代表环上第i个数是多少,po为dfs中当前环上第po个位置,prenum代表前环上前一个数字*/
        int ne = Next_prime[prenum];
        int d = ne - prenum;/*尝环将环后一个数字更改为d,ne一定是个质数*/
        while(d <= n )//n是环的长度
        {
            if(d > 0 && !is_used[d])
            {
                round[po] = d;
                is_used[d] = 1;
                dfs(po + 1);//尝试下一个位置的值
                is_used[d] = 0;//回溯
            }
            ne = Next_prime[ne];
            d = ne - prenum;/*下一次尝试时只需要ne = Next_prime[ne],保证ne仍是质数而且d增大了 */
        }
    }

  这样的好处,就是减少了判断是否是质数的次数,当然,这个trick也无法改变素数环本身数据指数增长的事实,只能稍稍简化运算。
  另外,当n为奇数时,一定不存在素数环,这是由于抽屉原理,一定有两个非一的奇数相邻,其和便为偶数了,如果不考虑这个的话,可能ac不了。

附:素数环个数 Gx <script type="math/tex" id="MathJax-Element-34">G(x) </script>
G(2)=1,G(4)=2,G(6)=2,G(8)=4,G(10)=96,G(12)=1024,G(14)=2880, <script type="math/tex" id="MathJax-Element-35">G(2) = 1, G(4) = 2, G(6) = 2, G(8) = 4, G(10) = 96, G(12) = 1024, G(14) = 2880, </script>
G(16)=81024,G(18)=770144,G(20)=6309300,G(22)=213812336 <script type="math/tex" id="MathJax-Element-36">G(16) = 81024, G(18) = 770144, G(20) = 6309300, G(22) = 213812336...</script>
可以看出来随着个数的增长,这个trick并没有太大用处…

猜你喜欢

转载自blog.csdn.net/zhongershuchong/article/details/78923471
今日推荐