【Code Pratice】—— 等差素数列、错误票据、神奇算式

1 | 等差素数列

题目

2,3,5,7,11,13,…是素数序列。
类似:7,37,67,97,127,157 这样完全由素数组成的等差数列,叫等差素数数列。
上边的数列公差为30,长度为6。
2004年,格林与华人陶哲轩合作证明了:存在任意长度的素数等差数列。
这是数论领域一项惊人的成果!
有这一理论为基础,请你借助手中的计算机,满怀信心地搜索:
长度为10的等差素数列,其公差最小值是多少?

思路

抓住题目的两个关键点:1. 等差数列2. 素数

  1. 等差数列中每前后项的差都是相等的,即存在一个确定的公差
  2. 素数列中每一项都是素数

思路大概如下

  1. 选定一个数作为后面构造等差数列的公差(因为题目要求最小公差,所以公差可以从1开始遍历选择)
  2. 选定一个素数作为等差素数列的首项(等差素数列的首项应是最小或最大的,为了方便计算,可选择2为每一次尝试的首项)
  3. 由这个首项 + 公差构造出后面每一项的值
  4. 判断这个等差数列中是否每一项都是素数,是则返回这个等差素数列,反之继续

逻辑代码

int ArithmeticPrimeSequence(int i_uNum)
{
    if (0 > i_uNum)
    {
        return 0;
    }
    vector<int> res;
    int ComRatioMin = 1;

    for (int i = 1; i < 1000; i++)
    {
        for (int j = 2; j < 10000; j++)
        {
            if (IsPrimeNum(j))
            {
                int tmp = j;
                res.push_back(tmp);
                for (int k = 1; k < i_uNum; k++)
                {
                    tmp += i;
                    if (IsPrimeNum(tmp))
                    {
                        res.push_back(tmp);
                    }
                    else
                    {
                        res.clear();
                        break;
                    }
                }
            }
            if (i_uNum == res.size())
            {
                ComRatioMin = i;
                break;
            }
        }
        if (i_uNum == res.size())
        {
            ComRatioMin = i;
            break;
        }
    }

    cout << "The minimum common ratio = [" << ComRatioMin << "]." << endl;
    cout << "Result sequence: [";
    for (int i = 0; i < res.size(); i++)
    {
        if (i == res.size() - 1)
        {
            cout << res[i] << "]." << endl;
        }
        else
        {
            cout << res[i] << " ";
        }
    }
    return 1;
}

2 | 错误票据

题目

某涉密单位下发了某种票据,并要在年终全部收回。
每张票据有唯一的ID号。全年所有票据的ID号是连续的,但ID的开始数码是随机选定的。
因为工作人员疏忽,在录入ID号的时候发生了一处错误,造成了某个ID断号,另外一个ID重号。
你的任务是通过编程,找出断号的ID和重号的ID。
假设断号不可能发生在最大和最小号。
输入格式
要求程序首先输入一个整数N(N<100)表示后面数据行数。
接着读入N行数据。
每行数据长度不等,是用空格分开的若干个(不大于100个)正整数(不大于100000),以-1结束每行输入
每个整数代表一个ID号。
输出格式
要求程序输出1行,含两个整数m n,用空格分隔。
其中,m表示断号ID,n表示重号ID

样例
输入1
2
5 6 8 11 9
10 12 9

输出1
7 9

输入2
6
164 178 108 109 180 155 141 159 104 182 179 118 137 184 115 124 125 129 168 196 -1
172 189 127 107 112 192 103 131 133 169 158 -1
128 102 110 148 139 157 140 195 197 -1
185 152 135 106 123 173 122 136 174 191 145 116 151 143 175 120 161 134 162 190 -1
149 138 142 146 199 126 165 156 153 193 144 166 170 121 171 132 101 194 187 188 -1
113 130 176 154 177 120 117 150 114 183 186 181 100 163 160 167 147 198 111 119 -1

输出2
105 120

思路

  1. 因为所有的ID都是连续的,所以先将所有ID进行排序
  2. 断号ID的特征就是它的上一个ID与下一个ID差值不为1
  3. 重复ID的特征就是前后两个ID值一样

逻辑代码

void WrongTicket(int i_uNum)
{
    vector<int> res;
    int BrokenNum = 0;
    int RepeatNum = 0;
    for (int i = 0; i < i_uNum; i++)
    {
        int tmp = 0;
        while (tmp != -1)
        {
            cin >> tmp;
            res.push_back(tmp);
        }
    }
    ort(res, true);
    for (int i = 0; i < res.size() - 1; i++)
    {
        if (res[i] == res[i + 1])
        {
            RepeatNum = res[i];
        }
        if ((res[i] != (res[i + 1] - 1)) && (res[i] != res[i + 1]))
        {
            BrokenNum = res[i] + 1;
        }
    }
    cout << "Broken number = [" << BrokenNum << "]" << endl;
    cout << "Repeat number = [" << RepeatNum << "]" << endl;
}

3 | 神奇算式

题目

由4个不同的数字,组成的一个乘法算式,它们的乘积仍然由这4个数字组成。
比如:

210 x 6 = 1260 
8 x 473 = 3784
27 x 81 = 2187 

都符合要求。
如果满足乘法交换律的算式算作同一种情况,那么,包含上边已列出的3种情况,一共有多少种满足要求的算式

思路

神奇算式有两个关键点

  1. 两个乘数的位数和 = 4
  2. 乘积的位数仍为 4,且这四位数是两个乘数的位数

大概思路如下:

  1. 确定两个乘数的范围

  2. 记录下两个数的数值,以及各个位的数字,并判断这两个数是否符合要求
    怎么记录各个位的数值?
    定义一个10长度的数组,如果0~9刚好对应各个数字,如果出现对应数字,数组对应位加一即可

  3. 判断乘积是否符合要求
    怎么对比乘积的四位数与乘数的四位数是否相同?
    通过使用上面定义的数组,获取该乘积的每一位,对应位的数值减一,如果最后数组中出现-1值,或非全0值,则证明四位数不相同

  4. 排除干扰项
    什么是干扰项?
    如下列两个式子看起来都是神奇算式
    30 * 51 = 1530
    51 * 30 = 1530
    这两个式子实际上属于同一个神奇算式,只是两个乘数位置对调了,如果不排除这个类型的式子的话,就会导致得到的结果存在多个重复项

怎么排除?
只需要判断当前的两个乘数是否存在于前面存下来的数组中即可

逻辑代码

int MagicFormula()
{
    vector<int> num(10, 0);
    vector<pair<int, int>> Mult;
    int res = 0;

    int min1 = 0;
    int max1 = 0; 
    int min2 = 0;
    int max2 = 0; 
    for (int i = 1; i <= 2; i++)
    {
        if (1 == i)
        {
            min1 = 1;
            max1 = 9;
            min2 = 123;
            max2 = 987;
        }
        else
        {
            min1 = 12;
            max1 = 98;
            min2 = 12;
            max2 = 98;
        }
        for (int j = min1; j <= max1; j++)
        {
            for (int k = min2; k <= max2; k++)
            {
                int sum = 0;
                if (IsValidMultiplier(j, k, num))
                {
                    sum = j * k;
                    int tmp = sum;
                    while (tmp)
                    {
                        num[tmp % 10]--;
                        tmp /= 10;
                    }
                    int cnt = count(num.begin(), num.end(), 0);
                    if (10 == cnt)
                    {
                        int cnt1 = count(Mult.begin(), Mult.end(), pair<int, int>(j, k));
                        int cnt2 = count(Mult.begin(), Mult.end(), pair<int, int>(k, j));

                        if (0 == cnt1 && 0 == cnt2)
                        {
                            Mult.emplace_back(j, k);
                            cout << j << " * " << k << " = " << sum << endl;
                            res++;
                        }
                    }
                }
                fill(num.begin(), num.end(), 0);
            }
        }
    }
    return res;
}

在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Ltd Pikashu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值