【问题标题】:Many for loops sumarized into one loop许多 for 循环总结为一个循环
【发布时间】:2013-04-04 20:29:58
【问题描述】:

我正在设计一个效率极低的幻方求解器,它会告诉您 3x3 正方形的解数。本质上,我必须将 3x3 数组中的每个元素填充到某个数字(例如 16),然后重置,移动到下一个元素并像两位数增加一样填充它们。我已经设法通过使用 9 个 for 循环来实现这一点,每个元素一个。但是如果我想做一个 5x5 的正方形,我必须写 25 个循环吗?

代码的for循环部分如下。有没有办法通过for循环来总结这个和for循环?

for (sq9=1; sq9<17 ; sq9++) {
     for (sq8=1; sq8<17 ; sq8++) {
          for (sq7=1; sq7<17 ; sq7++) {
               for (sq6=1; sq6<17 ; sq6++) {
                    for (sq5=1; sq5<17 ; sq5++) {
                          for (sq4=1; sq4<17 ; sq4++) {
                               for (sq3=1; sq3<17 ; sq3++) {
                                    for (sq2=1; sq2<17 ; sq2++) {
                                         for (sq1=1; sq1<17 ; sq1++) {
                                              if  ( check_the_square() ) count++;
                                                            }}}}}}}}}}

*** EDIT ***

问这个问题 7 年后,我是一家大公司的首席工程师,领导着一个敬业的团队。感谢那些在这里……温柔的人。感谢您对我的耐心,您的好意已经走了很长一段路

【问题讨论】:

标签: c loops for-loop iteration


【解决方案1】:

有不止一种方法可以将所有这些概括为任意数量的正方形,但我想到的第一个方法是将所有正方形存储在一个数组中,并像增加一个写在数字。

首先,让我们用一些易于编辑的常量抽象出正方形的数量及其值的范围:

#define NUM_SQUARES 9
#define MIN_VAL     1
#define MAX_VAL     16

现在,在您正在执行所有这些操作的任何函数中,声明一个 ints 数组并将它们全部设置为 MIN_VAL

int squares[NUM_SQUARES];
for (int i=0; i<NUM_SQUARES; i++) {
    squares[i] = MIN_VAL;
}

现在,我们将如何精确地增加正方形?简单:在第一个值上加一个;如果它溢出MAX_VAL,将其设置为MIN_VAL,然后继续下一个方块。如果它没有溢出,停止,我们可以检查当前的配置。如果所有的方格都溢出并且我们移过了数组的末尾,我们知道我们已经处理了所有可能的方格配置,我们可以结束整个事情。

这在代码中会是什么样子?像这样的:

int i = 0;
do {
    if (check_the_square()) count++;
    for (i=0; i<NUM_SQUARES; i++) {
        squares[i]++;
        if (squares[i] > MAX_VAL) {
            squares[i] = MIN_VAL;
        } else {
            break;
        }
    }
} while (i < NUM_SQUARES);

【讨论】:

  • 这里真正的问题是蛮力没有帮助。 3X3 将有超过 10^10 次迭代,而 5x5 是不可能的 10^30 次迭代......
  • 有人打我一拳。 :) 只是一个小的更正,它应该是squares[i] &gt; MAX_VAL,因为你的当前重置为 15..
  • @qPCR4vir 是的,我们明白了,但我正在学习如何用 C 来表达想法……除此之外,您还需要第一步进行优化。阅读问题的第一行。
  • @jwodder 谢谢!这就是我的意思。也很好解释。如果我想检查每个配置,forloop 中的check_the_square() 会在if 之前吗?
  • @ValentineBondar:不,因为如果正方形没有溢出,则循环 breaks。由于 1 小于 MAX_VAL,循环将把 {0,0,0,0,0,0,0,0,0} 变成 {1,0,0,0,0,0,0,0,0}
【解决方案2】:

有一些库可以生成所有排列,但如果您想自己做,您可以通过一组值来管理它,从所有值开始为 0 并以所有值结束为 16 .

const int SIZE = 3;
const int START_VALUE = 1;
const int FINAL_VALUE = 16;
int elements[3][3] = {START_VALUE};

然后定义一组函数来处理该数组。

// Will return false when all combinations have been tried.
bool has_next_permutation(int array[SIZE][SIZE]) {
    for (int i = 0; i < SIZE; ++i) {
        for (int j = 0; j < SIZE; ++j) {
            if (array[i][j] != START_VALUE) {
                // We're not back to all elements being 0, so we're not done.
                return true;
            }
        }
    }
    return true;
}

// Gets the next permutation.
// Increase the first element by 1, and if it hits 17, reset it and
// increase the second element by 1, etc.
void get_next_permutation(int array[SIZE][SIZE]) {
    for (int i = 0; i < SIZE; ++i) {
        for (int j = 0; j < SIZE; ++j) {
            array[i][j]++;
            if (array[i][j] <= FINAL_VALUE) {
                // Hasn't reached the final value yet.
                return;
            }
            array[i][j] = 0;
        }
    }
}

然后在这样的循环中使用它:

do {
    check_the_square();
    get_next_permutation(elements);
} while (has_next_permutation(elements));   

【讨论】:

    【解决方案3】:

    使用数组替换您的sq# 和一个计算下一次迭代的小算法...这里您基本上需要一个 +1 运算符来使用 9 位编写的 base-17 数字...

      char sq[9] = { 1, 1, 1, 1, 1, 1, 1, 1, 1 };
      int l = 8;
    loop:
      if (l==-1) goto end;
      if (++sq[l]==18) { sq[l--]=1; goto loop; }
      check_the_square();
      l = 8;
      goto loop;
    end:
      ...
    

    【讨论】:

    • 转到这里没问题:第一个是中断,第二个是继续。这里真正的问题是蛮力无济于事。 3X3 将有超过 10^10 次迭代,而 5x5 是不可能的 10^30 次迭代......
    猜你喜欢
    • 1970-01-01
    • 2019-09-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-03-10
    • 1970-01-01
    • 1970-01-01
    • 2014-03-21
    相关资源
    最近更新 更多