素数环问题
--C++实现,没搞明白全排列思路为啥出错
问题描述
从1到n这n个数摆成一个环,要求相邻的两个数的和是一个素数。
输出可能的方案数输入
整数n输出
可能的方案数
样例输入
2样例输出
2
思路分析
1. 数据初始化
初始化标记数组,其元素值为false
2. 递归判断
判断填入的第i个数是否合法
合法(与左边的数互质)
填数(判断是否填完,对于最后一个数要判断其与首个数是否互质)
填完,打印结果
尚未填完,递归下一个
不合法,选择下一种可能
代码(标志位思想)
#include <iostream>
#include <cmath>
using namespace std;
int a[21]={0};
bool b[21]={0};
int sum=0;
int n;
bool pd(int x,int y){
int temp=x+y;
for(int i=2;i<(temp);i++)
if(temp%i==0)
return 0;
return 1;
}
void ssh(int t){
//对于素数环中每个位置,尝试填入n个数
//若第i个数尚未填入且与前一个数互质,填入a[t]
//否则,尝试第i+1个数
for(int i=1;i<=n;i++){
//注意两个判断条件:1.是否填入2.是否与t-1位的数互质
if(!b[i]&&pd(a[t-1],i)){
b[i]=1;//标记数组
a[t]=i;
//cout<<t<<" "<<a[t]<<endl;
//首位互质
if(t==n){
if(pd(a[n],a[1])){
sum++;
//for(int j=1;j<=n;j++) cout<<a[j]<<" ";
//cout<<endl;
}
}
//a[t]填完后递归a[t+1]
else
ssh(t+1);
//返回时将标记位重置
b[i]=0;
}
}
}
int main(){
cin>>n;
ssh(1);
cout<<sum;
return 0;
}
归纳
void backtrack (int t){ //形参t为树的深度,根为1
if (t>n)
update(x); //扩展到叶子结点,得到了一组解决方案
else
for (int i=0; i<2; i++){ //每个结点有2个子树
x[t]=i;// 即0/1,表示第 t个元素是否是可选元素
if (constraint(t) && bound(t)) //判断当前结点是否是扩展结点
backtrack(t+1); //对当前结点进行扩展
}
}
其中:
约束函数constraint(t)和限界函数bound(t),称为剪枝函数。函数update(x)是更新解向量x的。约束函数constraint(t),一般可以从问题描述中找到。
在素数环问题中,我们其实用的就是归纳的伪代码,与之不同的是,我们没有把t>n这种情况单独拿出来在for循环外考虑,而是将if-else判断放进了for循环
拓展(伪代码2)
void backtrack (int t){ //形参t为树的深度,根为1
for (int i=0; i<2; i++){ //每个结点有n个子树
if (t>n) {
update(x); //扩展到叶子结点,得到了一组解决方案
break;
}
x[t]=i; //即0/1,表示第 t个元素是否是可选元素
if (constraint(t) && bound(t)) //判断当前结点是否是扩展结点
backtrack(t+1); //对当前结点进行扩展
x[t]=0;
}
}
这种方法对于本问题也适用,特别是全排列这种问题,本方法更合适。
不多我到现在也没有想明白,为什么我用全排列思想做这道题没做出来,先把代码贴上:
#include <iostream>
#include <algorithm>
#include <math.h>
using namespace std;
int a[21]={0};
int n;
int sum=0;
bool prime_num(int a,int b){
for(int i=2;i<int(sqrt(a+b));i++)
if(a+b%i==0)
return false;
return true;
}
void BackTrack(int t){
int i;
for(i=t;i<=n;i++){
swap(a[i],a[t]);
if(prime_num(a[i-1],a[i])){
if(i==n)
if(prime_num(a[1],a[n]))
{
sum++;
for(int j=1;j<=n;j++) cout<<a[j]<<" ";
cout<<endl;
}
else
BackTrack(i+1);
}
swap(a[i],a[t]);
}
}
int main()
{
cin>>n;
for(int i=1;i<=n;i++) a[i]=i;
BackTrack(1);
cout<<sum;
return 0;
}