【问题标题】:Generate two random numbers so that one is always greater than the other生成两个随机数,使一个总是大于另一个
【发布时间】:2020-06-29 20:59:12
【问题描述】:

我正在对我的函数myFunc()的以下问题进行压力测试。

有一座石桥连接两个城市。从一个城市开始的第一块石头上刻有1,最后一块石头在另一个城市的一侧。每个后续的石头上都有两个连续的数字,除了最后一个石头上可能有一个或两个数字,这取决于 N 的值。 石头可以排列为 1, (2, 3), (4, 5), (6, 7)...N。

给你一个数字N,代表最后一块石头上的最后一个数字;和数字 X。任务是找到从第一个城市一侧或第二个城市一侧到达刻有 X 的石头所需的最少跳跃次数。 注意:跳第一块石头算0跳。

示例: 输入: 2 10 3 5 1

输出: 1 0

说明: 测试用例 1:N = 10 的石头对齐方式如下: 1, (2, 3), (4, 5), (6, 7), (8, 9), 10 要在 X = 3 上跳跃,您只需要从第一个城市一侧跳一次(因为第一次跳石不计算在内),然后从第二个城市跳 4 次。所以 1 和 4 的最小值是 1。

测试用例 2:N = 5 的石头排列如下: 1, (2, 3), (4, 5) 要在 X = 1 上跳跃,您只需要从第一个城市一侧跳零次(因为第一次跳石不计算在内),从第二个城市一侧跳跃 2 次。所以 0 和 2 的最小值是 0。

#include <iostream>
#include <algorithm>
#include <ctime>
using namespace std;

int myFunc(int n, int p) {
    return p / 2;
}

int findJumps(int n, int p){
    return min(X /2, (N / 2) - (X / 2));
}
int main() {
    int n, x;
    srand(time(0));
    while(true) {

        n = rand() % 40 + 1; // I want n to be always greater than x
        x = rand() % 40 + 1;
        if(myFunc(n, x) != findJumps(n, x)) {
            cout << n << " " << x;
            break;
        }

        else cout << n << " " << x;
        cout << endl;
    }
    return 0;
}

我想要我的代码是在无限循环范围内生成 N 总是大于 X。我该如何强制执行此条件?

【问题讨论】:

  • 9 和 40 是从哪里来的?您总是可以先生成 x,然后生成 n 作为 x+1 到 40 之间的随机数,或者如果您不关心严格的上限,只需在生成时将 x 添加到 n。
  • 你为什么要在每个循环中调用 srand?一旦在循环之外会更好。
  • @Rup,对不起,我的错
  • 一个愚蠢但有效的解决方案:while(n &lt;= x) x = rand() % 40 + 1;。 (如果n 设置为可能的最小值,请注意无限循环的可能性)
  • 有什么理由不能创建两个随机数并在它们的顺序错误时交换它们?

标签: c++ algorithm random


【解决方案1】:

首先让我建议您避免使用rand(完全)和% 将其输出限制在特定范围内。如果您确实坚持这样做,请跳到下面的 C 库部分,以了解至少是半合理的方式。

现代图书馆

C++ 11 引入了一组新的类来生成随机数,并将随机数减少到指定范围。使用它们是一种混合包 - 某些部分(如播种)有点困难,而其他部分(如减少到一个范围)则相当简单 - 至少如果你关心做好这项工作。

我还要注意,如果 0 n 的下限必须是 2,而不是 1

使用 C++ 11 随机数生成类,您可以按照以下一般顺序执行操作:

std::mt19937 gen{ std::random_device()() };

// ...

int n = std::uniform_int_distribution<int>(2, 40)(gen);
int x = std::uniform_int_distribution<int>(1, n)(gen);

如果你真的关心随机数的质量,你可能想走得更远一些——现在,它只使用来自 std::random_device 的单个返回值作为生成器的种子,但 mt19937 生成器实际上具有比这更大的状态,因此更大的种子会更好。如果您想了解这一点,您可能希望以std::seed_seq 为起点。

C 库

如果您打算使用rand()% 将数字减少到正确的范围,我想我会先编写一个小函数来生成指定范围内的随机数1 :

int rand_range(int lower, int upper) { 
    int range = upper - lower;

    return rand() % range + lower;
}

然后我会用它来生成数字:

n = rand_range(2, 40);
x = rand_range(1, n);

[如上,n的下限必须为2。]

另一种可能性是生成这两个数字,然后如果它们的顺序错误,则交换它们。尽管如此,这仍然存在它们相等的可能性,并且消除这种可能性会更有效——因此前面的建议只是确保当您生成 x 时,它的开始总是严格小于 n


1. 请注意,除非rand() 的范围恰好是40 的倍数(这不太可能),否则像这样使用% 会产生有偏差的结果。如果您想做得更好,您可以查看https://stackoverflow.com/a/2999130/179910 以获得一些改进的方法——但是现代库部分中显示的标准分发确实是正确的方法。

【讨论】:

    【解决方案2】:

    正如 Mark Ransom 所指出的,我遇到的一个简单而好的解决方案是简单的检查 if(x &gt; n) swap(n, x)

    因此,驱动程序代码可能如下所示:

    int main() {
    int n, x;
    srand(time(0));
    while(true) {
    
        n = rand() % 40 + 1; // I want n to be always greater than x
        x = rand() % 40 + 1;
        if(x > n) swap(n, x);
        if(myFunc(n, x) != findJumps(n, x)) {
            cout << n << " " << x;
            break;
        }
    
        else cout << n << " " << x;
        cout << endl;
    }
    return 0;
    

    }

    【讨论】:

    • 严格来说,这不符合n总是大于x的规定要求。您没有考虑这两个值可能相同的可能性。如果你真的需要n严格大于x,你应该测试它们相等的情况,如果相等则重新选择。
    • 嗯,它解决了给定的问题。有没有其他方法可以做到这一点?
    猜你喜欢
    • 2014-12-27
    • 2014-01-16
    • 2013-05-20
    • 2013-01-06
    • 2016-02-20
    • 1970-01-01
    • 1970-01-01
    • 2018-04-21
    • 2023-01-03
    相关资源
    最近更新 更多