算法基础:素数环

题目描述:

  • 一个环由n个圈组成,将自然数1-n放入圈内,使得任意相邻圈的两个数之和均为素数。
  • 第一个圈的元素均为1。下图为n=6时的一个例子:
  • 程序样例
  • 输入为一个整数n
  • 6
  • 8
  • 输出分别为
  • 1 4 3 2 5 6
  • 1 6 5 2 3 4
  • 1 2 3 8 5 6 7 4
  • 1 2 5 8 3 4 7 6
  • 1 4 7 6 5 8 3 2
  • 1 6 7 4 3 8 5 2

解题思路:

  1. 首先能想到的就是暴力法,全排列然后去筛选结果,但是就是存在效率低的问题。
  2. 现使用深搜回溯来解决
  3. 素数判断采用埃筛法

具体代码如下:

/**
 * 一个环由n个圈组成,将自然数1-n放入圈内,使得任意相邻圈的两个数之和均为素数。
 * 第一个圈的元素均为1。下图为n=6时的一个例子:
 * 程序样例
 * 输入为一个整数n
 * 6
 * 8
 * 输出分别为
 * 1 4 3 2 5 6
 * 1 6 5 2 3 4
 * 
 * 1 2 3 8 5 6 7 4
 * 1 2 5 8 3 4 7 6
 * 1 4 7 6 5 8 3 2
 * 1 6 7 4 3 8 5 2
*/
#include<bits/stdc++.h>
using namespace std;

vector<vector<int>> res;

/**
 * @brief 检查tar是不是素数(埃筛法O(n*log(logn)))
 * @param tar 要判断是不是素数的目标
 * @return 如果tar是素数返回true,否则返回false
*/
bool checkPrim(int tar){
    if(tar <= 1) return false;
    vector<bool> flag(tar + 1, true);               //初始化全为素数
    flag[1] = false;                                //1不是素数
    int sq = sqrt(tar);
    for(int i = 2; i <= sq; ++i){
        if(!flag[i]) continue;                      //如果当前位置不是素数,继续判断
        for(int j = i * i; j <= tar; j += i){
            flag[j] = false;
            if(j == tar) return false;              //中间如果出现不是,就直接返回结果,节省计算
        }
    }
    return flag[tar];
}

/**
 * @brief 求解素数环
 * @param num 要求解的数,比如题目的6、8等
 * @param curNum 当前处理的数
 * @param tempRes 处理中间结果
 * @param flag 标记那些数已经访问
*/
void helper(const int &num, int curNum, vector<int> &tempRes, unordered_set<int> &flag){
    if(tempRes.size() == num && checkPrim(tempRes.back() + 1)){
        res.push_back(tempRes);
        return;
    }
    for(int i = 2; i <= num; ++i){
        if(0 == flag.count(i) && checkPrim(i + curNum)){
            tempRes.push_back(i);
            flag.insert(i);
            helper(num, i, tempRes, flag);
            flag.erase(i);
            tempRes.pop_back();
        }
    }
}
int main(){
    vector<int> tempRes;
    unordered_set<int> flag;
    tempRes.push_back(1);
    flag.insert(1);
    int num;
    cin>>num;
    helper(num, 1, tempRes, flag);
    for(auto each : res){
        copy(begin(each), end(each), ostream_iterator<int>(cout, " "));
        cout<<endl;
    }
    return 0;
}

测试如下:

6
1 4 3 2 5 6
1 6 5 2 3 4
8
1 2 3 8 5 6 7 4
1 2 5 8 3 4 7 6
1 4 7 6 5 8 3 2
1 6 7 4 3 8 5 2

测试的比较少,大家若测出问题,欢迎私信交流讨论,一起进步!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值