您的位置:首页 > 其它

HDU1016 Prime Ring Problem (回溯 + 剪枝)

2016-04-16 16:32 246 查看
本文链接:http://www.cnblogs.com/Ash-ly/p/5398684.html

题意:

  给你一个数字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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: