素数环问题

/*
    Name: 素数环问题
    Copyright: 
    Author: 巧若拙 
    Date: 14/12/18 22:17
    Description: 
素数环问题:把整数1~n填写到一个环中,要求每个整数只能填写一次,并且相邻两个数的和为素数。
易知n为偶数。
因为所有的数字地位相同,为避免重复,可确定第一个数字为1,从第二个数字开始递归处理。 
利用回溯思想枚举每个位置所有的可能值,根据条件找出所有可能的排列。
算法0:回溯算法框架1:先处理递归出口(即终点),再枚举各种可能值,递归搜索下一层。调用函数直接判断是否满足条件,这样无需记录和恢复标记值。     
算法1:回溯算法框架1:以空间换时间,定义数组b用来设置标记,再搜索下一层前后记录和恢复标记值。 
算法2:回溯算法框架2:先枚举各种可能值,再判断是否到达终点,若到达终点则输出结果,否则递归搜索下一层。 
算法2的搜索深度比算法1要少一层,但是不如算法1结构清晰。
算法3:非递归算法:自定义栈模拟算法2的递归过程,注意最后一个位置要单独恢复b[a[t]] = 0。 
*/

#include<iostream>
#include<cmath>

using namespace std;

const int N = 10; //整数个数
int lib[N+N] = {1,1,0};//筛法求素数 
int a[N+1];
int b[N+1];//当前数字是否被用过
int s = 0;

void Prime(int n);//筛法求素数
bool IsOk(int n, int key); //判断key的值是否已经出现过 
void Print();
void dfs(int t); //框架1 
void dfs1(int t); //框架2 
void dfs2(int t); //框架2 
void dfs3(); //非递归算法 

int main()
{
    int i;
    
    Prime(N+N-1);

    a[1]=1;
    b[1]=1;
    
    dfs(2);
    dfs1(2);
    //dfs2(2);
//    dfs3();
    
    return 0;
}

void Prime(int n) //筛法求素数
{
    for (int i=2; i<=n; i++)
    {
        if (lib[i])
           continue;
        for (int j=i+i; j<=n; j+=i)
            lib[j] = 1;
    }
    for (int i=2; i<=n; i++)
    {
        if (lib[i] == 0)
           cout << i << " ";
    }
    cout << endl; 
}

bool IsOk(int n, int key) //判断key的值是否已经出现过 
{
    for (int i=1; i<n; i++)
    {
        if (a[i] == key)
            return false;
    }
    return true;

void dfs(int t) //框架1,不记录标记,直接判断 
{
    if (t == N+1) //到达终点,输出结果 
    {
        if (lib[a[1] + a[t-1]] == 0)
           Print(); 
    }
    else
    {
        for (int i=2; i<=N; i++) //枚举各种可能值 
        {
            if (IsOk(t, i) && lib[i + a[t-1]] == 0) //满足条件 
            {
                a[t] = i;
                dfs(t+1); //搜索下一层 
            }
        }
    }
}

void dfs1(int t) //框架1,记录标记,以空间换时间 
{
    if (t == N+1) //到达终点,输出结果 
    {
        if (lib[a[1] + a[t-1]] == 0)
           Print(); 
    }
    else
    {
        for (int i=2; i<=N; i++) //枚举各种可能值 
        {
            if (b[i] == 0 && lib[i + a[t-1]] == 0) //满足条件 
            {
                a[t] = i;
                b[i] = 1; //修改标记 
                dfs1(t+1); //搜索下一层 
                b[i] = 0; //恢复标记 
            }
        }
    }
}

void dfs2(int t) //框架2 ,记录标记,以空间换时间  
{
    for (int i=2; i<=N; i++) //枚举各种可能值 
    {
        if (b[i] == 0 && lib[i + a[t-1]] == 0) //满足条件 
        {
            a[t] = i;
            b[i] = 1;  //修改标记 
            if (t == N) //到达终点,输出结果 
            {
                if (lib[a[1] + a[t]] == 0)
                   Print(); 
            }
            else
                dfs2(t+1); //搜索下一层 
            b[i] = 0;   //恢复标记 
        }
    }
}

void dfs3() //非递归算法 
{
    int t = 2;
    while (t >= 2)
    {
        while (++a[t] <= N) //枚举各种可能值,a[t]初始化为0 
        {
            if (b[a[t]] == 0 && lib[a[t] + a[t-1]] == 0)  //满足条件 
            {
                b[a[t]] = 1;  //修改标记  
                if (t == N)  //到达终点,输出结果 
                {
                    b[a[t]] = 0;  //恢复标记 
                    if (lib[a[1] + a[t]] == 0)
                    {
                        Print(); 
                        break;
                    }
                }
                else
                    t++;  //搜索下一层 
            }
        }
        a[t--] = 0; //回溯 
        b[a[t]] = 0; //恢复标记 
    }
}

void Print()
{
    cout << ++s << ": ";
    for (int i=1; i<=N; i++)
    {
        cout << a[i] << " ";
    }
    cout << endl; 
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值