素数环(nyoj 488)

29 篇文章 0 订阅

素数环

时间限制: 1000 ms  |  内存限制: 65535 KB
难度: 2
描述

有一个整数n,把从1到n的数字无重复的排列成环,且使每相邻两个数(包括首尾)的和都为素数,称为素数环。

为了简便起见,我们规定每个素数环都从1开始。例如,下图就是6的一个素数环。

输入
有多组测试数据,每组输入一个n(0<n<20),n=0表示输入结束。
输出
每组第一行输出对应的Case序号,从1开始。
如果存在满足题意叙述的素数环,从小到大输出。
否则输出No Answer。
样例输入
6
8
3
0
样例输出
Case 1:
1 4 3 2 5 6
1 6 5 2 3 4
Case 2:
1 2 3 8 5 6 7 4
1 2 5 8 3 4 7 6
1 4 7 6 5 8 3 2
1 6 7 4 3 8 5 2
Case 3:
No Answer

这个题开始交了三四遍都是超时= =.改着改着居然又改成WA了.....

我觉得素数环有一个关键的地方在于 如果输入N是奇数的话,由于起点从1开始,那么1-N之间一共有N / 2个偶数,N / 2 +1个奇数,也就是奇数的个数比偶数多一个,那么把这N个数排成一个环,必然有两个奇数是相邻的,而两个奇数之和是偶数,偶数不是素数,所以我们得出结论,.这样当N是奇数的时候,直接输出no answer.  还有一点 1也是素数环.

做题的时候我还犯了一个错误....n虽然最大只有19, 但是,素数判断最大是19+18 = 37, 而我刚开始只把记录素数的数组开到了20....所以后面出错了,不太应该.

剩下的就是dfs了.因为第一个数是1,所以我在初始化数组的时候就把0位置置成1了,选数字的时候直接从2开始选就可以.

素数环有一个特点,那就是相邻两个数的奇偶性一定不同,因为奇数加上奇数等于偶数,偶数加上偶数也是偶数,而偶数一定不是素数,所有也可以在选取这一元素的时候跟上一元素比较下奇偶性,如果奇偶性相同,那么直接跳过.

#include<stdio.h>
#include <string.h>
#define SIZE 40

int x;
bool flag;
bool prime [SIZE];
bool vis[SIZE];
int ans[SIZE];

void isprime ()
{//素数筛选法 是素数置0 不是置1
	int i, j;
	prime[0] = prime[1] = 1;
	prime[2] = 0;
	for(i = 2; i * i <= SIZE; i++)
	{
		if(!prime[i])
		{
			for(j = i + i; j <= SIZE; j += i)
			{
				prime[j] = 1;
			}
		}
	}
} 

void dfs(int cur)
{
	int i;
	if(cur == x && !prime[ans[cur - 1] + ans[0]])
	{//以为是环, 所以不要忘记判断第一个数和最后一个数相加是否也是素数
		flag = 1;
		for(i = 0; i < cur; i++)
		{
			printf("%d ", ans[i]);
		}
		printf("\n");
	}
	else
	{
		for(i = 2; i <= x; i++)
		{
			if(!vis[i] && !prime[ans[cur - 1] + i])
			{
				vis[i] = 1;
				ans[cur] = i;
				dfs(cur + 1);
				vis[i] = 0;
			}
		}
	}
}

int main (void)
{
	isprime();
	int n = 1;
	while (scanf("%d", &x))
	{
		if(x == 0)
			return 0;
		flag = 0;
		memset(vis, 0, sizeof(vis));
		memset(ans, 0, sizeof(ans));
		ans[0] = 1;
		printf("Case %d:\n", n++);
		if(x % 2 == 0 || x == 1)//如果是偶数或者是1才进行深搜,是奇数,直接no answer
			dfs(1);
		if(flag == 0)
		{
			printf("No Answer\n");
		}
	}
	return 0;
}






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值