【算法实验二】--【回溯法】--素数环问题

1008.素数环问题

时限:1000ms 内存限制:10000K  总时限:3000ms

描述

把1到20这重新排列,使得排列后的序列A满足:
a. 任意相邻两个数之和是素数
b. 不存在满足条件a的序列B使得:A和B的前k(0 <= k <= 19)项相同且B的第k+1项比A的第k+1项小。(即按字典序排列的第一项)

 

输入

没有输入。

 

输出

输出A,两个数字之间用一个空格隔开,第一个数字前面和最后一个数字后面没有空格。

 

输入样例

 

输出样例

 

提示

本题不提供输出样例。

解析:素数环是我第一次认真做这个题,刚开始的思路肯定是,第一个固定是1,从第二个开始,与第一个相加看是不是素数,如果是就直接进行下一个数的检验,如果不是就把第二个和后面几个依次相加直到找出一个素数为止。到第m个时,检验是否与a[m-1]个相加为素数,如是直接search(m+1)即可,如果不是将m与后面的每个数进行交换,如果找到就直接交换并且进行search(m+1),如果找不到就先换回来,即把m归位,(划重点!!)然后与剩下的交换,直到找到为止。最后的判断条件自然是m>20,而且还要a[1]+a[21]为素数才可以输出,不然就要返回上一层继续找。

此外,这个题目是回溯法找排列树,所以出现的模板是排列的模板,即有两个swap函数。回溯法可以生成两种树,排列树和子集树,二者是有差别的,我会在算法分类概述的回溯篇里中进行详细解释。

注:这里有个很坑的问题是我写完之后总是输出无穷个结果,最后查别人的代码才直到输出以后要加exit(0)表示结束进程,,,,希望各位注意。

代码如下:

#include <iostream>
#include <cmath>
#include <cstdio>
#include <algorithm>
using namespace std;
int a[21],cnt=0;
void init()
{
    for(int i=0;i<21;i++)
        a[i]=i;
}
int isprime(int num)
{
    int i,k;
    k=sqrt(num);
    for(i=2;i<k;i++)
    {
        if(num%i==0)
            return 0;
    }
    return 1;
}

void output()
{
    for(int i=1;i<21;i++)
    {
        cout<<a[i]<<‘ ‘;
    }
    cout<<endl;
}
void search(int m)
{
    if(m> 20)
    {
        if(!isprime(a[1]+a[20]))
            return ;
        else
        {
            output();
            exit(0);    //结束程序
        }
    }

    else
    {
        for(int i=m;i<21;i++)
        {
            swap(a[m],a[i]);
            if(isprime(a[m-1]+a[m]))
                search(m+1);
            swap(a[m],a[i]);
        }
    }
}
int main()
{
    init();
    search(2);
}
 

    原文作者:回溯法
    原文地址: https://blog.csdn.net/zhuge2017302307/article/details/85344871
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞