【搜索与回溯】 素数环 Prime Ring Problem

本文详细解析了一道关于素数环排列的算法题目,通过建立求素数函数和使用递归搜索,实现了将1至n的整数排列成环,使相邻数之和为素数的解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

原题链接:
JZOJ
↑各位dalao们不一定有账号↑
你谷友链
↑UVA的,没有UVA账号还交不了咧↑
什么??不知道UVA? 出门右转百度不谢

题目描述我就用JZOJ的啦,洛谷的是pdf

题目描述

输入正整数 n n n,把整数 1 , 2 , 3 , … … , n 1,2,3,……,n 123n组成一个环,使得相邻两个整数之和均为素数。输出时从整数 1 1 1开始逆时针排列。同一个环应恰好输出一次。按字典序由小到大输出所有可能的排列。

输入

一行,正整数 N ( 1 &lt; N &lt; = 16 ) N(1&lt;N &lt;= 16) N1<N<=16

输出

若干行,每行一个符合要求的排列,两个整数之间用一个英文输入法下的空格隔开(半角空格)。如果无符合要求的排列,输出“no answer”,不包含引号,两单词之间有一个半角空格。
样例输入
6
样例输出
1 4 3 2 5 6
1 6 5 2 3 4

解题思路:根据题目描述可得,一定要先建立一个求素数的函数,就取名为“p”吧,这个可以是布尔函数,是就返回true 不是就返回false (当然也可以用int类型,返回1或2)
之后就是找出口:当递归(搜索)函数执行到n+1次时,就进行判断,如果P(第一个数+第n个数)☜此处的括号代表的是函数调用。是true就可以进入循环,进行输出,但是要注意,输出的时候,循环从1到执行次数-1次
根据内容可知,如果无解,就要输出“no answer”,着怎么办好呢?就需要一个计数器(设为t吧),每输出一次就+1,这样,搜索完之后,如果t==0,就输出“no answer”。
到了最关键的搜索部分:
如果不是出口,就进入一个循环并判断,如果它没有被标记,而且和前一个数相加是素数,就把它标记,并进入下一次递归,然后又标回空的(回溯)

好了,该上代码了:

#include<iostream>
#include<cmath>
using namespace std;
int n,a[1001],b[1001],t=0;
bool p(int j){
	for(int i=2;i<=j-1;i++){
		if(j%i==0)
			return false;
	}
	return true;
}
void s(int x){
	if(x==n+1){
		if(p(a[n]+a[1])==true){
			for(int i=1;i<=x-1;i++){
				cout<<a[i]<<" ";
			}
			t++;
			cout<<endl;
		}
	}
	else
	{
		for(int i=1;i<=n;i++){
			if(b[i]==0 && p(a[x-1]+i)==true){
				a[x]=i;
				b[i]=1;
				s(x+1);
				b[i]=0;
			}
		}
	}
}
int main(){
	cin>>n;
	a[1]=1;
	b[1]=1;
	s(2);
	if(t==0){
		cout<<"no answer";
	}
	return 0;
	
}

但是,如果你是JZOJ的小朋友,就会发现,这回TLE(90),还差一个点啊woc!
所以,要优化!
再来!

#include<iostream>
#include<cstdio>
#include<cmath>//这里可以用Van能头噢
using namespace std;
int n,a[1001],b[1001],t=0;
bool p(int j){//判断素数
	for(int i=2;i<=j-1;i++){
		if(j%i==0)
			return false;
	}
	return true;
}
void s(int x){
	if(x==n+1){
		if(p(a[n]+a[1])==true){
			for(int i=1;i<=x-1;i++){
				printf("%d ",a[i]);//输出
			}
			t++;//累加,以防无解
			printf("\n");
		}
	}
	else
	{
		for(int i=1;i<=n;i++){
			if(b[i]==0 && p(a[x-1]+i)==true){
				a[x]=i;//交换
				b[i]=1;//标记
				s(x+1);//进入下一层递归
				b[i]=0;//回溯
			}
		}
	}
}
int main(){
	scanf("%d",&n);
	a[1]=1;
	b[1]=1;//这里1可是要重判的
	s(2);//要从2开始
	if(t==0){
		printf("no answer");//无解的时候
	}
	return 0;
	
}//其实改完之后,你会发现只改了printf,不过确实会比cout快一些!

不要老是Ctrl + C 和Ctrl + V啦
如有雷同,纯属巧合!

特别感谢@Coisini.小姐姐的帮忙

楼下隐形文字,扫描查看 !!

☟☟☟☟☟☟☟☟☟☟☟☟☟☟☟☟☟☟☟☟☟☟☟☟☟

哥哥姐姐们,写的辣么辛苦,不点赞,关个注再走嘛!?

☝☝☝☝☝☝☝☝☝☝☝☝☝☝☝☝☝☝☝☝☝☝☝☝☝

楼上隐形文字,扫描查看 !!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值