您的位置:首页 > 其它

NYOJ 488 素数环

2013-11-11 00:40 302 查看
题目:

http://acm.nyist.net/JudgeOnline/problem.php?pid=488
思路

“全排列”思想。

以“6”为例,

1 4 3 2 5 6
1 6 5 2 3 4


1.上面两组可以构成素数环,所谓“环”, 即循环,只取出全排列中以1开头的那部分就可以,换句话说,对2-6进行全排列就可以了。

2.“素数”,每两个的和必须是素数,注意素数的判定(前面整理过了);

3.“2-6”排列中的第一个数,要和1相加,判断一下和是否是素数;

4.“环”, 首尾要连接起来,也要判定是否构成素数;

实现

使用标记数组B,记录当前遍历到的数是否被选过(少用了一个判断,即else里面只有一个循环,时间明显提高);

改进的程序中,else里面只有一个循环,比之前提高了效率;

只有一个1的时候,也构成一个素数环;

当输入的数是除1之外的素数的时候,不用进入递归去判断,直接输出No answer就可以了, 同时也提高了时间效率(当初也就是改了这里,改正了超时的错误);

#include<stdio.h>
#include<string.h>

void Primes();
void PrimeCirculer(int n, int cur);
bool number[40] = {0};							//素数标记数组, 0 为素数,1为非素数;
bool B[200] = {0, 1};							//标记数组;
int A[20] = {0, 1};

int flag = 0;									//标记No Answer的情况;

int main(void)
{
int n, i = 1;								//i记录case个数;
Primes();
while(scanf("%d", &n), n != 0)
{
printf("Case %d:\n", i++);
if(n != 1 && n % 2 != 0)				//素数单独拿出来,减少判断;
{
printf("No Answer\n");
}
else
{
PrimeCirculer(n, 2);					//类似于只输出以1开头的全排列的一部分, 所以从2开始, 输出2-n的部分全排列,将下标为1的位置置1;
if(flag == 0)
printf("No Answer\n");
memset(A, 0, sizeof(A));
memset(B, 0, sizeof(B));
A[1] = 1;
B[1] = 1;
flag = 0;
}
}
return 0;
}
void Primes()									//素数标记成0, 否则标记为1;
{
int i, j;
for(i = 2; i * i < 40; i++)
{
if(number[i] == 0)
{
for(j = i + i; j < 40; j = j + i)
{
number[j] = 1;
}
}//if
}//for
}
void PrimeCirculer(int n,int cur)
{
int i, j;
if(cur == n + 1 )//
{
if(number[ A[1] + A
] == 0)
{
for(i = 1; i <= n; i++)
printf("%d ", A[i]);
flag = 1;//**
printf("\n");
}//if
}
else
{
for(i = 2; i <= n; i++)
{
if(B[i] == 0 && number[ A[cur - 1] + i ] == 0)
{
A[cur] = i;
B[i] = 1;
PrimeCirculer(n, cur + 1);
B[i] = 0;
}
}//for
}//else
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: