HDU 1016 Prime Ring Problem --- 经典DFS

  HDU 1016

  题意:输入一个数n,把1到n的自然数放到一个环里(第一个为1),保证相邻的两个数的和是素数。

  思路:第一个数填1,以后每个数判断该数和前一个数想加是否为素数,是则填,然后标记,近一步递归求解。 然后记得回溯,继续判断下一个和前一个数之和为素数的数。素数需要打表

/* HDU 1016 Prime Ring Problem --- 经典DFS */
#include <cstdio>
#include <cstring>

int n;
bool primer[45], visit[25]; //primer打素数表,visit标记是否访问
int a[25]; //数组a存储放置的数

/* 40以内素数打表 */
void getPrimer(){
    //因为n最大是20,所以只要打到40
    primer[0] = primer[1] = 1; //1表示不是素数
    for (int i = 2; i < 7; ++i){
        for (int j = i*i; j < 40; j+=i){
            primer[j] = 1; //1表示不是素数
        }//for(j)
    }//for(i)
}

/*dfs搜索 num为已填的数的数目*/
void dfs(int num){
    int i;
    //已全部填完且首位之和为素数 输出
    if (num == n && !primer[a[num - 1] + a[0]]){
        for (i = 0; i < num-1; ++i){
            printf("%d ", a[i]);
        }
        printf("%d
", a[i]);
        return;
    }
    else{
        for (i = 2; i <= n; ++i){
            //该数未用过且和上一个数之和为素数
            if (!visit[i] && !primer[a[num - 1] + i]){
                a[num] = i;
                visit[i] = 1;
                dfs(num + 1);  //递归填数
                visit[i] = 0; //回溯
            }
        }
    }
}

int main()
{
    int kase = 0;
    getPrimer();
    while (scanf("%d", &n) == 1){
        memset(visit, 0, sizeof visit);
        printf("Case %d:
", ++kase);
        visit[1] = 1; //1用过
        a[0] = 1; //第一个数是1
        dfs(1);
        printf("
");
    }

    return 0;
}
View Code
原文地址:https://www.cnblogs.com/tommychok/p/5058569.html