标签:
题意:
给你一个数字N(N <= 20),要求你把这N个数组成一个环,环内的数字不能重复,左右相邻的两个的和是素数。给出最后的答案。
思路:
利用回溯剪枝算法,N个数,每个数有N种状态,枚举这N个状态,枚举过程中剪枝优化。
代码:
#include <cstdio>
#include <iostream>
#include <cstring>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <algorithm>
using namespace std;
const int MAXN = 43;
int n;
//素数表
int isprime[MAXN] = {0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0};
//判断是否重复
int used[MAXN];
//素数环
int circle[MAXN];
//判断 第 key 个位置的数字是否合法
int check(int key)
{
if( used[ circle[key] ] ) //之前被用过
return 0;
if(!isprime[ circle[key] + circle[key - 1] ])//和前面一个组成了非素数
return 0;
if(key == n && !isprime[ circle[key] + 1 ])//最后一个数和第一个数的和也不能是素数
return 0;
return 1;
}
void backtrack(int key)
{
if(key > n)//回溯完毕 打印结果
{
for(int i = 1; i <= n; i++)
cout <<(i == 1? "" : " ") << circle[i];
cout <<endl;
}
else
{
for(int i = 2; i <= n; i++) //这个位置一共有 n - 1 个状态,分别枚举
{
circle[key] = i;
if( check( key ) ) //剪枝处理
{
used[i] = 1; //标记这个点已被用
backtrack(key + 1);
used[i] = 0; //恢复现场
}
}
}
}
int main()
{
int kas = 1;
while(cin >> n)
{
printf("Case %d:\n", kas++);
memset(used, 0, sizeof(used));
memset(circle, 0, sizeof(circle));
circle[1] = 1; //第一个数字从 1 开始
backtrack(2); //从第二个数字开始求解
cout << endl;
}
return 0;
}
HDU1016 Prime Ring Problem (回溯 + 剪枝)
标签:
原文地址:http://www.cnblogs.com/Ash-ly/p/5398684.html