搜索入门练习题1 素数环 题解

Posted zifeiynoip

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了搜索入门练习题1 素数环 题解相关的知识,希望对你有一定的参考价值。

题目出处:《信息学奥赛一本通》例5.1。

题目描述

素数环:从 \(1\)\(n(2 \le n \le 20)\)\(n\) 个数摆成一个环,要求相邻的两个数的和是一个素数。

输入格式

输入包含一个整数 \(n(2 \le n \le 20)\)

输出格式

按字典序从小到大的顺序输出所有排列方案,每个排列方案占一行。每行的 \(n\) 个数之间由一个空格分隔。

样例输入

2

样例输出

1 2
2 1

问题分析

很明显,这是一道可以用搜索解决的问题,我们可以采用“回溯”思想,使用深度优先搜索解决这个问题。
我们用 ans[] 数组来存放我们当前遍历到的答案, ans[id] 用于表示当前排列的第 id 个数是什么。所以我们可以开一个函数 void f(int id) 来表示要在第 id 个位置放数,我只需要从 1 到 n 遍历每一个数(我这里假设是 i),并判断 i 是否能放。
在第 id 个位置能放 i 当且仅当:

  • \(ans[1]\)\(ans[id-1]\) 都不等于 \(i\),即 \(i\) 之前没有放过;
  • \(id \gt 1\) 时,满足 \(ans[id-1]+ans[id]\) 是素数;
  • \(id = n\) 时,满足 \(ans[1] + ans[n]\) 是素数。

这样,我们递归地调用 f(id) ,当 id>n 时就是我们递归的边界条件;一旦 id>n 就说明我找到了一种方案。
实现代码如下:

#include<bits/stdc++.h>
using namespace std;
int ans[22], n;
bool isp(int a)    // 判断a是否是素数
    if (a < 2) return false;
    for (int i = 2; i * i <= a; i ++) if (a%i==0) return false;
    return true;

void output()      // 输出一种排列方案
    for (int i = 1; i <= n; i ++)
        cout << (i>1 ? " " : "") << ans[i];
    cout << endl;

void f(int id)     // 搜索函数,在第id个位置尝试放上一个数
    if (id > n)    // 边界条件
        if (isp(ans[1]+ans[n])) output();
        return;
    
    for (int i = 1; i <= n; i ++)  // 遍历i = 1 to n ,看看第id个位置能否放i
        bool flag = true;
        if (id > 1 && !isp(ans[id-1]+i)) flag = false;
        if (flag) 
            for (int j = 1; j < id; j ++)
                if (ans[j] == i) 
                    flag = false;
                    break;
                
        
        if (flag) 
            ans[id] = i;
            f(id+1);
        
    

int main() 
    cin >> n;
    f(1);
    return 0;

以上是关于搜索入门练习题1 素数环 题解的主要内容,如果未能解决你的问题,请参考以下文章

算法练习--素数环

搜索入门练习题4 数的拆分 题解

搜索入门练习题3 全组合 题解

搜索入门练习题5 八皇后问题 题解

搜索入门练习题6 马的遍历 题解

搜索入门练习题7 最高效益和 题解