算法第一次作业-Problem C. Superprime

题目描述

农民约翰的母牛总是生产出最好的肋骨。你能通过农民约翰和美国农业部标记在每根肋骨上的数字认出它们。
农民约翰确定他卖给买方的是真正的质数肋骨,是因为从右边开始切下肋骨,每次还剩下的肋骨上的数字都组成一个质数,举例来说:
7 3 3 1
全部肋骨上的数字 7331是质数;三根肋骨 733是质数;二根肋骨 73 是质数;当然,最后一根肋骨 7 也是质数。

7331 被叫做长度 4 的特殊质数。
写一个程序对给定的肋骨的数目 N (1< =N< =8),求出所有的特殊质数。数字1不被看作一个质数。

在这里插入图片描述在这里插入图片描述
这种题对于数学能力稍弱一些的人来说如何去思考是一件困难的事情。
我们首先需要明确的是,不加优化的枚举肯定会超时。网上会发现很多厉害的人有很高级的优化。
我们可以去考虑

打表:
打表,是一信息学专用术语,意指对一些题目,通过打表技巧获得一个有序表或常量表,来执行程序某一部分,优化时间复杂度。这种算法也可用于在对某种题目没有最优解法时,用来得到分数的一种策略。
简单来说:打表,又可以叫自欺欺人算法,属于应试技巧,然而并没有任何增长水平的意义。
鉴于目前考试的类型和方式,打表还是很重要的。就是暴力写出题目中要求求的东西,然后去发现规律并暴力输出。

有时正是打表得到的最简便的解法。
在此题中我们发现n只有8个,质数肋骨的数量很有限,完全可以预先算好数据,而不是提交计算程序让它慢慢跑。
第一步:暴力得到所有的数据

# include <stdio.h>
# include <stdbool.h>
bool f1(int );
bool f2(int );
int main(void)
{
    int i;
    for(i=1;i<99999999;i++)  //暴力循环所有的八位数
    {
        if( f1(i) )  //如果f1得到的为true,证明使我们题目所求的那些数之一,应当输出
            printf("%d  ",i);
    }
    return 0;
}
bool f1(int n)
{
    while(n)
    {
        if(f2(n))  //f2用来证明n已经是素数
        {
            n=n/10;  //这个很重要!请自己试数 例如:7331/10=733
        } 
        else
        {
            return false;  //只要有一次不符合题目要求就返回false
        }
    }
    return true;
}
bool f2(int n)
{
    if(1 == n)
    {
        return false;  //题目要求:数字1不能看做质数
    }
    else if(2 == n)
    {
        return true;  
    }
    else
    {
        int i;
        for(i=2;i<n;i++)  //这个都懂,求素数嘛 优化:可以从2到2/n 或到sqrt(n)
        {
            if( 0 == (n%i) )
            {
                return false;
            }
        }
    }
    return true;
}

素数:只能被1和它本身整除的数称为素数。2是一个特殊的素数,因为它能被1和它本身整除。

第二步:根据第一步暴力得出来的所有解进行归类
当AC测试输入1的时候会有哪些结果要出现,2的时候呢?。。。8的时候呢?这样再写起来就很简单了。

#include <stdio.h>
int N[8][20]={{2,3,5,7},{23,29,31,37,53,59,71,73,79},{233,239,293,311,313,317,373,379,593,599,719,733,739,797},{2333,2339,2393,2399,2939,3119,3137,3733,3739,3793,3797,5939,7193,7331,7333,7393},{23333,23339,23399,23993,29399,31193,31379,37337,37339,37397,59393,59399,71933,73331,73939},{233993,239933,293999,373379,373393,593933,593993,719333,739391,739393,739397,739399},{2339933,2399333,2939999,3733799,5939333,7393913,7393931,7393933},{23399339,29399999,37337999,59393339,73939133}};
int a[8]={4,9,14,16,15,12,8,5};  //表示每位数的数量
int main(void)
{
    int n;
    scanf("%d",&n);
    int i;
    for(i=0;i<a[n-1];i++)  //用a这个数组加下标来确定要输出几个数
    {
        printf("%d\n",N[n-1][i]);
    }
    return 0;
}

有些算法确实关乎数学,有时我们并不能想出一个很好的解决办法,所以我们需要看懂别人的程序。
这是b站上C语言讲解最全面全程手敲代码的郝斌老师所说的话,尤其希望算法题练得少的同学认真尝试一下。
看懂一个算法的步骤:
1、看懂流程控制
2、看懂每个语句的功能
3、试数

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值