Prime Ring Problem——HDU1016

 

Prime Ring Problem

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 40419    Accepted Submission(s): 17843


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.

Prime Ring Problem——HDU1016_第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
 

Source
Asia 1996, Shanghai (Mainland China)
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int prime[] = {3,5,7,11,13,17,19,23,29,31,37};//当n小于20时两个数之和最大的素数为37
int primeflag[39];//用于快速判断是否为素数,当元素值为1时当前数为素数
int visited[21];//用于标记当前数是否使用过,值为-1时为使用过,0表示没有使用过
int ans[21];//存储答案的数组
void dfs(int n)//深搜加回溯,为避免超时使用非递归方法
{
    int flag = 0;//表示当前正在填数的前一个位置
    int i = 2;//从2开始到n搜索能填入的数字
    while(flag >= 0) {//当flag<0时表明所有解都已求出
        while(i <= n) {//当i>n时表示当前位置所有数字都已经试过了
            if(visited[i] != -1 && primeflag[ans[flag] + i] == 1) {//当 当前数字没有被试过而且满足与后一个数字之和为素数时填入数字
                ans[++flag] = i;
                visited[i] = -1;
                i = 2;//每填入一个数字之后循环变量要初始化为2表示下一个位置要重新开始搜索
                }
             else i++;
        }

        if(flag == n - 1 && primeflag[ans[flag] + 1] == 1) {//当上一个while循环结束后flag已经到了最后一个位置并且第一个数与最后一个数满足和为素数时表明当前有一个解
            for(int j = 0; j < n - 1; j++) {
                cout << ans[j] << " ";
            }
            cout << ans[n - 1] <<  endl;//最后一个数后面没有空格
        }
        i = ans[flag];//回溯时保存当前位置已经填过的数
        visited[i] = 0;//将这个数重新标记为没有使用过
        i++;//数字i在flag处已经试过,下一次循环时只要从i++这个数开始即可避免重复产生死循环
        flag--;//往后回退一个位置表示重新填写flag+1位置处的数字--回溯
    }
}
int main()
{
    int n,ncase = 0;
    for(int i = 0; i < 11; i++) {
        primeflag[prime[i]]= 1;
    }
    while(cin >> n) {
        memset(visited,0,sizeof(visited));
        memset(ans,0,sizeof(ans));
        ans[0] = 1;
        visited[1] = -1;
        ncase++;
        cout << "Case " << ncase <<":" << endl;
        if(n % 2 == 0)//能满足题意产生输出的只有当n为偶数时才可以,因为可行解中必须是奇数偶数交替排列,当n为奇数排列时会多出一个奇数
            dfs(n);
        cout <<endl;
    }
    return 0;
}


你可能感兴趣的:(ACM,杭电)