【问题标题】:How To Efficiently Check If 10 Variables Are Different如何有效检查 10 个变量是否不同
【发布时间】:2014-09-01 06:37:41
【问题描述】:

我正在尝试使用 c++ 解决以下数学问题:

(Each letter represents an individual digit)

  WHITE
+ WATER
-------
 PICNIC

到目前为止,我有这个代码来解决这个难题:

#include <iostream>

using namespace std;

int main(int argc, char **argv) {
  for (int w = 5; w < 10; w++) {
    for (int h = 0; h < 10; h++) {
      for (int i = 0; i < 10; i++) {
        for (int t = 0; t < 10; t++) {
          for (int e = 0; e < 10; e++) {
            for (int a = 0; a < 10; a++) {
              for (int r = 0; r < 10; r++) {
                for (int p = 0; p < 10; p++) {
                  for (int c = 0; c < 10; c++) {
                    for (int n = 0; n < 10; n++) {
                      // I need to check if all the digits are different here
                      if (10000 * w + 1000 * h + 100 * i + 10 * t + e + 10000 * w + 1000 * a + 100 * t + 10 * e + r == 100000 * p + 10000 * i + 1000 * c + 100 * n + 10 * i + c) {
                          cout << "W: " << w << endl;
                          cout << "H: " << h << endl;
                          cout << "I: " << i << endl;
                          cout << "T: " << t << endl;
                          cout << "E: " << e << endl;
                          cout << "A: " << a << endl;
                          cout << "R: " << r << endl;
                          cout << "P: " << p << endl;
                          cout << "C: " << c << endl;
                          cout << "N: " << n << endl;
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}

我可以运行一些快速测试来检查所有数字是否不同(有 10 个不同的字母,所以一个必须是 0,一个必须是 1,等等)

编辑:

我尝试将它们相加并检查是否等于 45。我可以编写另一个程序/方法在嵌套循环完成后清除结果,但有没有更好的方法?

【问题讨论】:

  • 将每个字符添加到std::set,并检查下一个字符是否已存在于集合中。
  • @NeilKirk 这速度够快吗?因为会有大量可能的迭代,我不希望它永远持续下去。
  • @NeilKirk:这回答了标题中提出的问题,但是如果您阅读问题正文中的代码,它甚至根本不会做任何事情。
  • @Puppy:那是因为他不知道怎么做,所以他还没有写那段代码。
  • 将它们全部加起来,看看它们是否加到 45。虽然不完美,但会清除大部分误报,剩下的你可以看一下。

标签: c++ conditional-statements


【解决方案1】:

你可以使用以下

return ((1 << W)
     | (1 << H)
     | (1 << I)
     | (1 << T)
     | (1 << E)
     | (1 << A)
     | (1 << R)
     | (1 << P)
     | (1 << C)
     | (1 << N))
     == 0x03FF;

【讨论】:

  • 正是我想要的(除了大写字母:))。你介意解释一下它是如何工作的吗?
  • 它是位左移和位或,它假定您的号码在[0..31] 范围内,您可以查看en.wikipedia.org/wiki/Bitwise_operation 了解更多详情
  • 提示:0x3FF 是二进制的 11 1111 1111(十个)。
  • 如果你问我,这个答案值得更多的支持纯粹的代码fu。它本质上是在做“使用哈希表来跟踪你所看到的”的解决方案,但它通过使用int 作为比特大小的桶的“哈希表”来非常有效地做到这一点。
【解决方案2】:

将除w 中的数字之外的所有数字放在std::vector 中,并使用 std::next_permutation 遍历它们的所有排列,将它们分配给您的字母:

std::vector<int> letters(9);

for(int w=5;w!=10;++w)
{
  for(int i=0;i!=9;++i) letters[i] = (i<w) ? i : i+1;

  do
  {
    int h = letters[0];
    int i = letters[1];
    //etc
  }
  while(std::next_permutation(letters.begin(), letters.end()));
}

然后,您将通过构造将数字有效分配给字母,并且无需检查它们是否不同,从而将性能提高一千倍(具体多少取决于平均成本) std::next_permutation)。

编辑

实际上,再想一想,我意识到您可以更轻松地做到这一点

std::vector<int> letters(10);
letters[0] = 5;
for(int i=0;i!=9;++i) letters[i+1] = (i<5) ? i : i+1;

do
{
  int w = letters[0];
  int h = letters[1];
  int i = letters[2];
  //etc
}
while(std::next_permutation(letters.begin(), letters.end()));

由于next_permutation 按字典顺序迭代排列,所以letters[0] 不能小于5。

【讨论】:

  • 这显着减少了迭代次数(解决问题的更好方法),但我仍然需要一种比较整数的方法。
  • @cabellicar123:不,你不会。 letters 的元素保证是唯一的,因此一旦将它们分配给变量,它们不能包含重复的数字。不过,您仍然需要检查总和。
  • 对不起,你是对的。我不知道我在想什么。
【解决方案3】:

免责声明:Jarod42 的回答是正确的。

我发布代码的唯一原因是我很惊讶地发现有一个 W

#include <iostream>
#include <numeric>
#include <algorithm>
#include <array>

int white(const std::array<int, 10>& x)
{
    // W H I T E A R P C N
    return 10000 * x[0] + 1000 * x[1] + 100 * x[2] + 10 * x[3] + 1 * x[4];
}

int water(const std::array<int, 10>& x)
{
    // W H I T E A R P C N
    return 10000 * x[0] + 1000 * x[5] + 100 * x[3] + 10 * x[4] + 1 * x[6];
}

int picnic(const std::array<int, 10>& x)
{
    // W H I T E A R P C N
    return 100000 * x[7] + 10010 * x[2] + 1001 * x[8] + 100 * x[9];
}

int main(int, char *[])
{
    std::array<int, 10> x;

    std::iota(x.begin(), x.end(), 0);

    do {
        if (white(x) + water(x) == picnic(x)) {
            std::cout << white(x) << " + " << water(x) << " = " << picnic(x) << "\n";
        }
    } while (std::next_permutation(x.begin(), x.end()));

    return 0;
}

注意:我已准备好反对投票...我只需要下班休息 15 分钟。

【讨论】:

  • 在数学上是否不可能有一个解决方案 W &lt; 5 因为下一个最高的 4 + 4 即使带有 1 结转仍然只会产生 9 不足以获得第 6 名数字。
  • @cabellicar123 P 可以为 0。
  • 你说的非常对。我没有考虑过这种情况。我假设在原始问题中,他们打算将 PICNIC 设为 6 位数字。也很高兴我能给你这样的休息和不错的速度!
  • 通过使用WHITEAR 的所有排列、计算WHITE + WATER 的总和并确定该总和是否满足PICNIC 的要求,代码可能会快一个数量级。跨度>
猜你喜欢
  • 2015-08-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-11-21
  • 1970-01-01
  • 1970-01-01
  • 2011-11-20
  • 2013-06-21
相关资源
最近更新 更多