您的位置:首页 > 其它

hdu 1016 Prime Ring Problem

2012-09-13 15:37 411 查看
Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)

Total Submission(s): 14516 Accepted Submission(s): 6623



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

6
8


Sample Output

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




题意: 有N个数字, 依次为1~N, 然后要令这些数字练成一个圆圈, 并且要相邻两个数字的和是一个素数,将所有情况依次输出,并且都是从 1 开始输出。

思路: 两个偶数 或者 两个奇数相加是个偶数, 偶数一定不是素数, 所以N 为奇数时,是没有满足的数字串,输出空行。

然后就用 递归回溯 依次暴力一遍。 每确定一个数字就到下个数字, 满了n个就输出, 回溯的上一个,看还有无其他符合的数字。

深搜, 每次只要考虑 当前要确定的数字 和 上一个确定的数字 的和是否为素数, 和数字是否重复用过。

模拟 N = 6;(希望耐心看)

首先 : 1 是确定的。

数组 : num[] = 1 __ __ __ __ __; visitied[] = 1 0 0 0 0 0;

然后开始递归了(深搜) 每次都从 2 (i == 2) 数字开始找。 判断 i 与 上个确定的数 是否满足条件 if( (i + num[x - 1]) 是素数 && i 未被访问(使用,出现)

结果 是: num[] = 1 2 __ __ __ __; visited[] = 1 1 0 0 0 0;

然后递归到下一个要确定的数字; 同理

结果是: num[] = 1 2 3 __ __ __; visited[] = 1 1 1 0 0 0 ;

接着依次是: num[] = 1 2 3 4 __ __; visited[] = 1 1 1 1 0 0;

接着找不到了 因为 4 与 5 和 6 都是合数。4位置就退出递归,将4位置的数字回溯,visited[i][j] = 0; 比较为未访问: num[] = 1 2 3 __ __ __; visited[] = 1 1 1 0 0 0;

退到3后, 3 与 5 和 6 的和都是合数,同理 回溯: num[] = 1 2 __ __ __ __; visited[] = 1 1 0 0 0 0;

退到2后,2 与 5 的和是素数 num[] = 1 2 5 __ __ __; visited[] = 1 1 0 0 1 0;

接着递推: num[] = 1 2 5 6 __ __; visited[] = 1 1 0 0 1 1;

6与 3 和 4 的和都是合数 回溯: num[] = 1 2 5 __ __ __; visited[] = 1 1 0 0 1 0;

5 已经循环到 6 了 退出递归。 回溯:1 2 __ __ __ __;

2 和 6 的和是合数:1 4 __ __ __ __(继续循环) -> 1 4 3 __ __ __ (递归)-> 1 4 3 2 __ __ (递归) -> 1 4 3 2 5 __ (递归) -> 1 4 3 2 5 6 (递归);

满了, 判断头尾的和是否为素数 1 + 6 == 素数 则输出: 1 4 3 2 5 6

然后退出递归,继续回溯: 1 4 3 2 5 __ -> 1 4 3 2 __ __ (回溯)-> 1 4 3 __ __ __(回溯) -> 1 4 __ __ __ __(回溯) -> 1 6 __ __ __ __(继续循环)

然后继续递归 1 6 5 __ __ __ (递归) -> 1 6 5 2 __ __(递归) -> 1 6 5 2 3 __ (递归) -> 1 6 5 2 3 4(递归);

满了, 同理 1 + 4 == 素数 输出: 1 6 5 2 3 4;

继续 回溯:1 6 5 2 3 __ -> 1 6 5 2 __ __ -> 1 6 5 __ __ __ -> 1 6 __ __ __ __ -> 1 __ __ __ __ __ (循环完退出最外面的dfs(), 程序退出);

递归 可以理解成 深搜, 往更里深搜, 回溯可以理解成 将递归的所访问的 恢复到没访问。

#include <stdio.h>
#include <string.h>
#define max_size 25
int n, count = 1, num[max_size], visited[max_size];
int p[40] = {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};
void dfs(int x) {
if(x > n && p[1 + num
]) {
printf("%d", num[1]);
for(int i = 2; i <= n; ++i)
printf(" %d", num[i]);
printf("\n");
return;
}
for(int i = 2; i <= n; ++i) {
if(!visited[i] && p[num[x - 1] + i]) {
visited[i] = 1;
num[x] = i;
dfs(x + 1);
visited[i] = 0;
}
}
}
int main() {
while(~scanf("%d", &n)) {
memset(visited, 0, sizeof(visited));
num[1] = 1;
printf("Case %d:\n", count++);
if(n % 2 == 0)
dfs(2);
printf("\n");
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: