hdu 1016

题目概述

一个由从1开始递增的自然数构成的环,其上共N个数,环上任意相邻两数之和为素数,给定N,以1为环上第一个数,按字典序输出所有满足条件的环

输入

每行一个正整数N

限制

0

输出

每组输出第一行为Case #:其中#为数据序数,第二行为所求的环上的数,两个数之间有一空格,每组输出后有一空行

样例输入

6
8

样例输出

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

讨论

没那么复杂,按这数据规模用深搜即可,本来打算偷懒用stl自带的next_permutation函数,不过那个毕竟是全排列,复杂度太高,深搜的话只要干两件事,其一检查是否已达环上要求的数字的个数,其二就是为当前位置分配一个数字
需要注意的是每行最后不能有空格,否则会PE,至于最后一行的空行,没有影响
可能还有更加高效的方法,但是额没打算深究这个题,事实上把所有结果都准备好,按N的值直接输出这些答案,这恐怕是最快的方法,不过这样做毫无意义,额也不打算去尝试

题解状态

717MS,1744K,1138 B,C++

题解代码

#include<stdio.h>
#include<algorithm>
#include<set>
using namespace std;
#define INF 0x3f3f3f3f  
#define maxx(a,b) ((a)>(b)?(a):(b))  
#define minn(a,b) ((a)<(b)?(a):(b))  
#define MAXN 21
#define memset0(a) memset(a,0,sizeof(a))

set<int>prime{ 1,2,3,5,7,11,13,17,19,23,29,31,37,41,43,47 };//数据规模到20为止 因而考虑40以内的素数足以 1实际上并没用上
int N;//环上数字个数
int times = 0;//数据序数 先+1后输出
int nums[MAXN];//存放环上的数
bool marked[MAXN];//检查该数字以否在环上已出现过 这比用set高效不少 但素数用布尔数组会很不直观
bool f;//控制空格输出
inline bool check(int n, int num)//内联的检查相邻两数和的函数 只是为了让代码更清晰而分离出来
{
    if (prime.find(nums[n - 1] + num) == prime.end())//不是素数
        return false;
    return true;
}
void dfs(int n)//深搜 n是当前的位置序号
{
    if (n == N) {//如果位数已经足够
        if (check(n, 1)) {//最后检查环的两端是否符合 开头肯定是1
            for (int p = 0; p < N; p++) {
                if (f)
                    printf(" ");//output
                printf("%d", nums[p]);//output
                f = 1;
            }
            printf("\n");//output
            f = 0;
            return;
        }
        else//不符合就直接返回
            return;
    }
    for (int p = 1; p <= N; p++)
        if (!marked[p] && check(n, p)) {//在环上没出现过 并且满足素数条件
            nums[n] = p;//确定这一位的数字
            marked[p] = 1;//标记之
            dfs(n + 1);//去深搜下一位
            marked[p] = 0;//深搜后解除标记
        }
}
void fun()
{
    printf("Case %d:\n", ++times);//output
    nums[0] = 1;//第一个数肯定是1
    marked[1] = 1;
    dfs(1);//从环上第二个数开始深搜
    printf("\n");//output
}
int main(void)
{
    //freopen("vs_cin.txt", "r", stdin);
    //freopen("vs_cout.txt", "w", stdout);

    while (~scanf("%d", &N)) {//input
        fun();
    }
}

EOF

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值