解説
有一个整数n,把从1到n的数字无重复的排列成环,且使每相邻的两个数(包括首和尾)的和都为素数,称为素数环。为了简便起见,我们规定每个素数环都从1开始。例如,6的一个素数环:
1 4 3 2 5 6
请编写一个程序,给定一个输入n(0<n<20),如果存在满足要求的素数环,从小到大输出。否则,输出No Answer。
私はdfsとバックトラッキングメソッドを使用してこの質問を行いました。バックトラッキングプロセスも非常に単純です。他のブログで間違いなく話しますが、dfsプロセスにはトリックがあると思います。非常に良いと思います。ここで共有してください:
まず最初に配列を定義する
int Next_prime[1001];//Next_prime[i]表示大于i的最小的质数
次に、メイン関数で初期化します
{
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增大了 */
}
}
これの利点は、素数であるかどうかを判断する回数を減らすことです。もちろん、このトリックでは、素数リング自体のデータが指数関数的に増加するという事実を変えることはできません。計算を少しだけ簡単にすることができます。
さらに、nが奇数の場合は、素数のリングが存在しないようにする必要があります。これは引き出しの原理によるものです。互いに隣接する2つの1以外の奇数が必要であり、合計は偶数になります。これを考慮しない場合、ACは不可能になる場合があります。
付属:素数リングの数 G ( × ) <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>
数が増えるにつれて、このトリックはあまり役に立たないことがわかります...