随机选择扬声器顺序的算法可以工作但通常会产生无限循环

时间:2016-10-02 01:48:39

标签: c

我创建了以下算法(用于真正的问题和乐趣),以便随机确定在辩论中向七名学校董事会候选人提问的顺序,以便:

  • 每位候选人被问到7个​​问题
  • 每个候选人在位置1,位置2等处恰好回答一次
  • 候选人并不总是遵循相同的顺序(随机顺序但受限于前两条规则)

此算法可以工作,产生受规则限制的随机输出,但通常会无限循环(或出现)。我已经无法确定为什么会发生这种情况,尽管单步执行其他日志/断点的代码。

注意:此算法尚未推广或优化。

{{1}}

3 个答案:

答案 0 :(得分:6)

这是算法中的一个缺陷。

我在内部print_debate_order()循环中添加了for以查看程序获得了多远。这是在进入无尽的时间之前的最后一个循环的一个输出:

Questions #0
  Candidate #2
  Candidate #6
  Candidate #1
  Candidate #3
  Candidate #0
  Candidate #5
  Candidate #4
Questions #1
  Candidate #0
  Candidate #3
  Candidate #4
  Candidate #2
  Candidate #5
  Candidate #1
  Candidate #6
Questions #2
  Candidate #4
  Candidate #2
  Candidate #6
  Candidate #5
  Candidate #3
  Candidate #0
  Candidate #1
Questions #3
  Candidate #5
  Candidate #4
  Candidate #0
  Candidate #1
  Candidate #6
  Candidate #3
  Candidate #2
Questions #4
  Candidate #3
  Candidate #5
  Candidate #2
  Candidate #0
  Candidate #4
  Candidate #6
  Candidate #-1
Questions #5
  Candidate #-1
  Candidate #-1
  Candidate #-1
  Candidate #-1
  Candidate #-1
  Candidate #-1
  Candidate #-1
Questions #6
  Candidate #-1
  Candidate #-1
  Candidate #-1
  Candidate #-1
  Candidate #-1
  Candidate #-1
  Candidate #-1

正如你所看到的,对于问题4,只剩下一个候选人,即候选人1.但是如果你看看之前的问题,你会发现他已经有问题2的最后一个位置。因此,没有候选人被允许取问题4的最后一个位置,你的while循环试图无休止地找到一个。

如果你想从所有作业中统一选择满足你条件的问题,你就必须在这样的事情发生时重新开始,即你的while循环需要跟踪已经测试过的候选人,如果没有一切都必须从头开始。然而,这也将在非常长的时间内结束,具体取决于候选人和问题的数量,但至少不会有无限循环。

您要在此处生成的内容称为(uniformly distributed) latin square。生成它们不一定是微不足道的,here is a discussion on math.stackexchange.com

答案 1 :(得分:1)

在调试随机参与程序时请记住,始终生成器的种子(此处为enum Whatever { case number(Int) case value(String) } let myArray: [Whatever] = [.number(8), .number(6), .number(9), .value("John"), .value("Frederick")] myArray.forEach { switch $0 { case .number(let numberOfLetters): // Do something break case .value(let value): // Do something break } } )应该是静态的,直到算法运行(至少对于该种子) - 然后是种子应该是可控制的,至少在你确信它一直在工作之前。报告种子也值得。

例如替换:

srand

srand((unsigned int)time(NULL));

您可以更改种子以获得所需的错误,然后进行处理。

原因是你总是得到相同的随机数集,然后调试就会简单得多。

答案 2 :(得分:0)

在下面的重写中,我使用@Eichhörnchen的分析并将其重新设计为拉丁方生成问题。我使用了简单的拉丁方逻辑,意图是你可以将它升级到更好的逻辑。我还尝试通过将更多问题域引入变量命名来攻击行和列混合:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#define NUM_CANDIDATES 7
#define NUM_QUESTIONS 7

int debate_order[NUM_QUESTIONS][NUM_CANDIDATES];

void print_debug_order() {

    for (int question = 0; question < NUM_QUESTIONS; question++) {

        for (int candidate = 0; candidate < NUM_CANDIDATES; candidate++) {
            printf("%d ", debate_order[question][candidate] + 1);
        }

        printf("\n");
    }
}

void print_debate_order() {

    for (int question = 0; question < NUM_QUESTIONS; question++) {
        printf("Question #%d\n", question + 1);

        for (int candidate = 0; candidate < NUM_CANDIDATES; candidate++) {
            printf("\tCandidate #%d\n", debate_order[question][candidate] + 1);
        }
    }
}

// based on http://benpfaff.org/writings/clc/shuffle.html
void shuffle_array(int array[], size_t length) {

    for (int i = 0; i < length - 1; i ++) {
        int random = i + rand() / (RAND_MAX / (length - i) + 1);

        int temporary = array[random];
        array[random] = array[i];
        array[i] = temporary;
    }
}

void generate_latin_square(int square[NUM_QUESTIONS][NUM_CANDIDATES]) {

    int candidates[NUM_CANDIDATES];

    for (int candidate = 0; candidate < NUM_CANDIDATES; candidate++) {
        candidates[candidate] = candidate;
    }

    shuffle_array(candidates, NUM_CANDIDATES);

    for (int candidate = 0; candidate < NUM_CANDIDATES; candidate++) {
        for (int question = 0; question < NUM_QUESTIONS; question++) {
            square[question][candidates[candidate]] = (question + candidate) % NUM_CANDIDATES;
        }
    }
    // print_debug_order();
}

int main(int argc, const char *argv[]) {
    srand(time(NULL));

    generate_latin_square(debate_order);

    print_debate_order();

    return 0;
}

要查看解决方案核心的拉丁方,请取消注释print_debug_order()

<强>更新

虽然我的代码在候选人数=问题数时起作用,但我尝试使它们不相等并且对结果不满意。我重做了它,所以它现在起作用,如果#candidate!=#questions。请注意,当问题数&gt;时,OP的要点3会轻微受到影响。候选人数量,但仍然可以产生可行的结果。 (候选人数量&gt;问题数量没有此问题。)