Prime Ring Problem
Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 60401 Accepted Submission(s): 26099
Problem Description
A ring is compose of n circles as shown in diagram. Put natural number 1, 2, ..., n into each circle separately, and the sum of numbers in two adjacent circles should be a prime.
Note: the number of first circle should always be 1.
Input
n (0 < n < 20).
Output
The output format is shown as sample below. Each row represents a series of circle numbers in the ring beginning from 1 clockwisely and anticlockwisely. The order of numbers must satisfy the above requirements. Print solutions in lexicographical order.
You are to write a program that completes above process.
Print a blank line after each case.
Sample Input
68
Sample Output
Case 1:1 4 3 2 5 61 6 5 2 3 4Case 2:1 2 3 8 5 6 7 41 2 5 8 3 4 7 61 4 7 6 5 8 3 21 6 7 4 3 8 5 2
Source
Asia 1996, Shanghai (Mainland China)
Regionals 1996 >> Asia - Shanghai
问题链接:UVa524 UVALive5270 HDU1016 ZOJ1457 Prime Ring Problem。
问题简述:
输入一个数n(0<n<20),用1到n的整数围成一个圈,使得相邻的两个数之和为素数,输出各种可能的圈。
本题可以使用深度优先搜索求解。程序中,函数dfs()的参数为已经有几个数满足相邻为素数,其功能是寻找下一个满足条件的数。
问题分析:
因为是一个圈,并且用1到n的整数都要被用到,所以将1固定在一个位置上。这样做也可以减少重复的搜索。
程序说明:
需要注意的是,HDU1016的格式与UVA524的格式略为不同,空行的位置不同。
对于HDU1016与UVA524,分别编写了一个根据快速简洁的C++的版本。
AC的C++语言程序如下(HDU1016,快速简洁版):
/* HDU1016 Prime Ring Problem */
#include <iostream>
#include <stdio.h>
#include <math.h>
#include <string.h>
using namespace std;
#define N 20
int prime[N * 2];
int ans[N];
int visited[N];
int n, flag;
// Eratosthenes筛选法
void sieveofe(int p[], int n)
{
int i, j;
p[0] = 0;
p[1] = 0;
p[2] = 1;
// 初始化
for(i=3; i<n; i++) {
p[i++] = 1;
p[i] = 0;
}
int max = sqrt(n);
for(i=3; i<=max; i++){
if(p[i]) {
for(j=i+i; j<=n; j+=i) //进行筛选
p[j]=0;
}
}
}
void print_result()
{
int i;
for(i=1; i<=n; i++) {
if(i != 1)
printf(" ");
printf("%d", ans[i]);
}
printf("\n");
}
void dfs(int count)
{
int i;
if(count == n) {
if(prime[ans[count] + ans[1]])
print_result(); // 输出结果
} else {
for(i=2; i<=n; i++)
if(!visited[i] && prime[i + ans[count]]) {
ans[count + 1] = i;
visited[i] = 1;
dfs(count + 1);
visited[i] = 0;
}
}
}
int main(void)
{
sieveofe(prime, N * 2 -1);
int caseno=0;
while(scanf("%d", &n) != EOF) {
// 初始化标志
memset(visited, 0, sizeof(visited));
printf("Case %d:\n",++caseno);
// 深度优先搜索并且输出结果
ans[1] = 1;
visited[1] = 1;
flag = 1;
dfs(1);
printf("\n");
}
return 0;
}
AC的C语言程序如下(HDU1016):
/* HDU1016 ZOJ1457 Prime Ring Problem */
#include <stdio.h>
#include <memory.h>
#include <math.h>
#define MAXN 20
int ans[MAXN];
int visit[MAXN];
int n, count;
// 试除法判断一个数是否为素数
int isprime(int n)
{
if((n & 1) == 0) // 偶数:n % 2 == 0
return 0;
if(n == 3)
return 1;
int end = sqrt(n), i;
for(i=3; i<=end; i+=2) {
if(n % i == 0)
break;
}
return i > end ? 1 : 0;
}
void print_result()
{
int i;
for(i=1; i<=n; i++) {
if(i != 1)
printf(" ");
printf("%d", ans[i]);
}
printf("\n");
}
void dfs(int count)
{
int i;
for(i=2; i<=n; i++)
if(!visit[i]) {
if(isprime(ans[count] + i)) {
count++;
if(count == n) {
if(isprime(i + ans[1])) {
ans[count] = i;
print_result(); // 输出结果
}
} else {
ans[count] = i;
visit[i] = 1;
dfs(count);
visit[i] = 0;
}
count--;
}
}
}
int main(void)
{
int caseno=0;
while(scanf("%d", &n) != EOF) {
// 初始化标志
memset(visit, 0, sizeof(visit));
printf("Case %d:\n",++caseno);
// 深度优先搜索并且输出结果
count = 1;
ans[1] = 1;
visit[1] = 1;
dfs(count);
printf("\n");
}
return 0;
}
AC的C++语言程序如下(UVA524,快速简洁版):
/* UVA524 UVAlive5270 Prime Ring Problem */
#include <iostream>
#include <stdio.h>
#include <math.h>
#include <string.h>
using namespace std;
#define N 20
int prime[N * 2];
int ans[N];
int visited[N];
int n, flag;
// Eratosthenes筛选法
void sieveofe(int p[], int n)
{
int i, j;
p[0] = 0;
p[1] = 0;
p[2] = 1;
// 初始化
for(i=3; i<n; i++) {
p[i++] = 1;
p[i] = 0;
}
int max = sqrt(n);
for(i=3; i<=max; i++){
if(p[i]) {
for(j=i+i; j<=n; j+=i) //进行筛选
p[j]=0;
}
}
}
void print_result()
{
int i;
for(i=1; i<=n; i++) {
if(i != 1)
printf(" ");
printf("%d", ans[i]);
}
printf("\n");
}
void dfs(int count)
{
int i;
if(count == n) {
if(prime[ans[count] + ans[1]])
print_result(); // 输出结果
} else {
for(i=2; i<=n; i++)
if(!visited[i] && prime[i + ans[count]]) {
ans[count + 1] = i;
visited[i] = 1;
dfs(count + 1);
visited[i] = 0;
}
}
}
int main(void)
{
sieveofe(prime, N * 2 -1);
int caseno=0;
while(scanf("%d", &n) != EOF) {
// 初始化标志
memset(visited, 0, sizeof(visited));
if(caseno != 0)
printf("\n");
printf("Case %d:\n",++caseno);
// 深度优先搜索并且输出结果
ans[1] = 1;
visited[1] = 1;
flag = 1;
dfs(1);
}
return 0;
}
AC的C语言程序如下(UVA524):
/* UVA524 UVALive5270 Prime Ring Problem */
#include <stdio.h>
#include <memory.h>
#include <math.h>
#define MAXN 20
int ans[MAXN];
int visit[MAXN];
int n, count;
// 试除法判断一个数是否为素数
int isprime(int n)
{
if((n & 1) == 0) // 偶数:n % 2 == 0
return 0;
if(n == 3)
return 1;
int end = sqrt(n), i;
for(i=3; i<=end; i+=2) {
if(n % i == 0)
break;
}
return i > end ? 1 : 0;
}
void print_result()
{
int i;
for(i=1; i<=n; i++) {
if(i != 1)
printf(" ");
printf("%d", ans[i]);
}
printf("\n");
}
void dfs(int count)
{
int i;
for(i=2; i<=n; i++)
if(!visit[i]) {
if(isprime(ans[count] + i)) {
count++;
if(count == n) {
if(isprime(i + ans[1])) {
ans[count] = i;
print_result(); // 输出结果
}
} else {
ans[count] = i;
visit[i] = 1;
dfs(count);
visit[i] = 0;
}
count--;
}
}
}
int main(void)
{
int caseno=0;
while(scanf("%d", &n) != EOF) {
// 初始化标志
memset(visit, 0, sizeof(visit));
if(caseno != 0)
printf("\n");
printf("Case %d:\n",++caseno);
// 深度优先搜索并且输出结果
count = 1;
ans[1] = 1;
visit[1] = 1;
dfs(count);
}
return 0;
}