关于相邻两数之和为素数的解答

 题目:巧排数字。将1、2、...、20这20个数排成一排,使得相邻的两个数之 和为一个素数,且首尾两数字之和也为一个素数。编程打印出所有的排法。

    先说下这道题的思路,肯定是应该用回溯的方法。穷举则运算的量太大不适合,而递归空间复杂度也太大。

先放入第一个数 1,然后依次放入2、3、4···,每次放入时判断与前一个数之和是否为素数,若是则继续放入,若不是则回退一步,选后一个数。这样直到放完。

 伪算法:

0. 初始化 标记所有数在每个位置都能放置。

1. 从剩下的数选最小的一个且能在此位置放置的,放入数组,若没有数满足到3,若已放完到4.

2. 判断放入的数与前一个数之和是否为素数(第一个不判断,最后一个要与它前一个和第一个数判断)
    是素数回到1,不是素数,标记此数不能在这个位置放置到1.

3. 回退一步,即将前面一个数取出,并且标记此位置之后的位置,所有数都能放置。到1.

4. 打印出结果。到5.

5. 判断是否退空,若没退空到3.。退空结束。

这里我将放数,退数模仿成进栈、出栈。然后输出结果到文件时声明了

一个友元函数,方便一些。

下面是源代码 ( 编译器 VC++ 8.0 )

// Stack.h
#ifndef STACK_H
#define  STACK_H


class  Stack
{
    
public :
        Stack();
        
bool  Push();    
        
bool  Pop();        
        
void  Display();
        
bool  IsFull();
        
int  GetTop();
        
long  TheCount();

        friend 
void  FileDisplay( const  Stack & );         // 输出到文件
    
    
private :
        
bool  IsPrime( int );

    
private :
        
long  count;                 // 解数
         int  top;
        
int  value[ 21 ];             // 结果
         bool  state[ 21 ][ 21 ];      // 状态    [位置][数]
};
#endif    // STACK_H
/// :~

 

// Stack.cpp
#include  " Stack.h "
#include 
< iostream >
#include 
< fstream >
#include 
< cstring >      // memset()
#include  < math.h >
using   namespace  std;



Stack::Stack()
{
    memset(value,
0 , 21 * sizeof ( int ));
    memset(state,
true , 21 * 21 * sizeof ( bool ));
    top
= 0 ;
    count
= 0 ;
}
void  Stack::Display()
{
    
for ( int  i = 1 ;i <= 20 ;i ++ )
        cout
<< value[i] << " " ;
    cout
<< endl;
}

bool  Stack::IsFull()
{
    
return  (top == 20 );
}

bool  Stack::Push()
{
      
if (top == 20 )     // 已填完
          return   false ;
    
    top
++ ;
    
for ( int  i = 1 ;i <= 20 ;i ++ )
    {
        
// 测试i是否满足
         if (state[top][i])
        {
            
bool  flag = true ;
            
for ( int  j = 1 ;j < top;j ++ )
            {
               
// 判断前面是否用过此数
                 if (value[j] == i)
                {
                    flag
= false ;
                    
break ;
                }
            }
            
if (flag)
            {
    
if (top == 20 )                
    {
          
if ( ! IsPrime(i + value[ 1 ]))     // 最后一个数要判断与第一个数之和是否为素数
          {
                 state[
20 ][i] = false ;
                 
continue ;
           }
    }                                
                     
if (IsPrime(i + value[top - 1 ]))     // 判断与其前一个数之和是否为素数
                    {                    
                            state[top][i]
= false ;
                            value[top]
= i;
           
if (top == 20 )
                count
++ ;            // 填完
                             return   true ;
                     }
                     
else
                     {
                           state[top][i]
= false ;
                     }
            }
        }
    }
    top
-- ;
    
return   false ;     // 没有满足条件的数 返回false
}

bool  Stack::Pop()
{
       
if (top == 0 )           // 栈空返回false
            return   false ;
       state[top][value[top]]
= false ;
       memset(state[top
+ 1 ], true , 21 * sizeof ( int ));     // 其后位置所有数可再用        
       value[top] = 0 ;
       top
-- ;
      
return   true ;
}

bool  Stack::IsPrime( int  e)
{
    
if (e % 2 == 0 )
        
return   false ;
    
for ( int  i = 3 ;i <= sqrt(( float )e);i += 2 )
    {
        
if (e % i == 0 )
            
return   false ;
    }
    
return   true ;
}

int  Stack::GetTop()
{
    
return  top;
}

long  Stack::TheCount()
{
    
return  count;
}

void  FileDisplay( const  Stack &  a)
{
       ofstream 
out ( " Answer.txt " ,std::ios_base::app);
       
out << " No. " << a.count << endl;
       
for ( int  i = 1 ;i <= 20 ;i ++ )
            
out << a.value[i] << " " ;
       
out << endl;
}

 

memset(char* ,value,long)这个函数初始化比较快一点,它把起始于某一特定地址的内存(该内存作为第一个参数)从起始地址直至气候的n(n作为第三个参数)个字节的所有内存都设置成同一个特定的值(该值作为第二个参数)

 

// main.cpp
#include  < iostream >
#include 
" Stack.h "
using   namespace  std;

int  main()
{
    Stack a;
    
bool  s = true ;

    
while (s)     // 循环直到栈空,即不能再回退,则所有已测试完
    {
         
if (a.Push())
         {
/* 继续往内填数 */ }
         
else
         {
              s
= a.Pop();     // 不能再填则回退一步        
         }
         
if (a.IsFull())
         {            
             FileDisplay(a);
         }
     }    
     
return   0 ;
}

这个结果共有1千多万组,这是不考虑相对位置即不把它看成一个圆。

若有高手有更好算法,还请指点。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,我会为您解答这个问题。 您可以尝试使用以下方法来解决这个问题: 1. 定义一个数组来存储当前环中的数字序列。 2. 编写一个函数来检查给定的两个数字之和是否为素数。 3. 编写一个递归函数来尝试构建一个素数环。该函数应该接受两个参数:当前环的长度和当前环中最后一个数字。 4. 在递归函数中进行以下操作: - 如果当前环的长度为n,检查最后一个数字和第一个数字之和是否为素数。如果是素数,则输出当前环中的数字序列。 - 否则,对于可以使用的每个数字,检查该数字和最后一个数字之和是否为素数。如果是素数,则将该数字添加到数字序列中,并递归调用该函数来构建比当前环多一个数字的环。 5. 在主程序中调用递归函数,并输出所有找到的素数环。 以下是使用 C 语言编写的示例代码: ```c #include <stdio.h> int is_prime(int n) { // 判断一个数是否为素数 int i; if (n < 2) return 0; for (i = 2; i * i <= n; i++) { if (n % i == 0) { return 0; } } return 1; } void find_prime_rings(int n) { int a[16], i; // 初始化数字序列 for (i = 0; i < n; i++) { a[i] = 0; } // 从数字 1 开始尝试构建素数环 for (i = 1; i <= n; i++) { a[0] = i; find_next_prime_ring(1, i, a, n); // 开始递归构建素数环 } } void find_next_prime_ring(int k, int last, int a[], int n) { int i; // 如果当前环的长度为n,检查最后一个数字和第一个数字之和是否为素数 if (k == n) { if (is_prime(a[0] + last)) { // 输出当前环中的数字序列 printf("%d", a[0]); for (i = 1; i < n; i++) { printf(" %d", a[i]); } printf("\n"); } return; } // 对于可以使用的每个数字,检查该数字和最后一个数字之和是否为素数 for (i = 1; i <= n; i++) { if (a[i - 1] == 0 && is_prime(i + last)) { a[k] = i; // 将该数字添加到数字序列中 find_next_prime_ring(k + 1, i, a, n); // 递归调用该函数来构建比当前环多一个数字的环 a[k] = 0; // 回溯 } } } int main() { int n; scanf("%d", &n); find_prime_rings(n); return 0; } ``` 对于输入的 n=6 和 n=8,程序将输出以下两个素数环: ``` 1 4 3 2 5 6 1 6 5 2 3 4 7 8 ``` 希望能对您有所帮助!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值