是的,这是作业作业。但是,我不希望得到答案。
我应该编写一个程序来输出所有可能的解决方案,如下所示:
+-+-+-+
|2|7|6|
+-+-+-+
|9|5|1|
+-+-+-+
|4|3|8|
+-+-+-+
之前
+-+-+-+
|2|9|4|
+-+-+-+
|7|5|3|
+-+-+-+
|6|1|8|
+-+-+-+
因为276951438小于294753618。
我可以使用for循环(不是嵌套)和if else。解决方案必须按升序排列。我还需要知道这些东西有时看起来更有趣 //比睡觉。
目前,我有:
// generate possible solution (x)
int a, b, c, d, e, f, g, h, i, x;
x = rand() % 987654322 + 864197532;
// set the for loop to list possible values of x.
// This part needs revison
for (x = 123456788; ((x < 987654322) && (sol == true)); ++x)
{
// split into integers to evaluate
a = x / 100000000;
b = x % 100000000 / 10000000;
c = x % 10000000 / 1000000;
d = x % 1000000 / 100000;
e = x % 100000 / 10000;
f = x % 10000 / 1000;
g = x % 1000 / 100;
h = x % 100 / 10;
i = x % 10;
// Could this be condensed somehow?
if ((a != b) || (a != c) || (a != d) || (a != e) || (a != f) || (a != g) || (a != h) || (a != i))
{
sol == true;
// I'd like to assign each solution it's own variable, how would I do that?
std::cout << x;
}
}
How would I output in ascending order?
我之前编写过一个程序,它将用户输入的九位数字放在指定的表中,并验证它是否符合条件(如果每行的总和= 15, n 是幻方解,每个col = 15的总和,每个对角线的总和= 15)所以我可以处理那个部分。我只是不确定如何使用for循环生成九个数字整数的完整列表。有人可以告诉我如何做到这一点以及如何改进我目前的工作?
答案 0 :(得分:0)
这个问题在我不久前回答SO: magic square wrong placement of some numbers时引起了我的注意。
// I'd like to assign each solution it's own variable, how would I do that?
我不会考虑这个。每个找到的解决方案都可以立即打印(而不是存储)。向上计数循环授予输出按顺序。
我只是不确定如何使用for循环生成九个数字整数的完整列表。
答案是Permutation。
在OP的情况下,这是一组9个不同的元素,所有这些元素都具有不同顺序的所有序列。
9位数的可能解决方案数量由factorial计算:
9! = 9·8·7·6·5·4·3·2·1 = 362880
从字面上看,如果要检查9位数的所有可能顺序,则循环必须进行362880次迭代。
谷歌搜索一个准备好的算法(或至少是一些灵感)我发现(令我惊讶的是)C ++ std
Algorithms library实际上为此准备好了:
将范围
[first, last)
转换为相对于operator<
或comp
按字典顺序排列的所有排列集合中的下一个排列。如果存在这样的排列,则返回true
,否则将范围转换为第一个排列(如std::sort(first, last)
所示)并返回false
。
让事情变得更棘手的是关于禁止数组的限制。假设阵列禁止也禁止std::vector
和std::string
,我调查了OP使用一个整数的想法。
32位int
涵盖[-2147483648,2147483647]的范围,足以存储数字1 ... 9:987654321的最大排列。(可能是,std::int32_t
将是更好的选择。)
提取具有除法和10的模幂的个别数字有点单调乏味。将该集合存储为基数16的数字简化了事情。单个元素(也称为数字)的隔离现在变为按位运算(&
,|
,~
,<<
和>>
)的组合。反向抽取是32位不再足以满足九位数 - 我使用了std::uint64_t
。
我在class Set16
中填充了内容。我考虑提供引用类型和双向迭代器。在摆弄了一段时间之后,我得出的结论是,这并不容易(如果不是不可能的话)。根据cppreference.com上提供的示例代码重新实现std::next_permutation()
是我更容易的选择。
362880行的输出对于演示来说有点多。因此,我的样本为3个较小的3位数组做了! (= 6)解决方案:
#include <iostream>
#include <cassert>
#include <cstdint>
// convenience types
typedef unsigned uint;
typedef std::uint64_t uint64;
// number of elements 2 <= N < 16
enum { N = 3 };
// class to store a set of digits in one uint64
class Set16 {
public:
enum { size = N };
private:
uint64 _store; // storage
public:
// initializes the set in ascending order.
// (This is a premise to start permutation at first result.)
Set16(): _store()
{
for (uint i = 0; i < N; ++i) elem(i, i + 1);
}
// get element with a certain index.
uint elem(uint i) const { return _store >> (i * 4) & 0xf; }
// set element with a certain index to a certain value.
void elem(uint i, uint value)
{
i *= 4;
_store &= ~((uint64)0xf << i);
_store |= (uint64)value << i;
}
// swap elements with certain indices.
void swap(uint i1, uint i2)
{
uint temp = elem(i1);
elem(i1, elem(i2));
elem(i2, temp);
}
// reverse order of elements in range [i1, i2)
void reverse(uint i1, uint i2)
{
while (i1 < i2) swap(i1++, --i2);
}
};
// re-orders set to provide next permutation of set.
// returns true for success, false if last permutation reached
bool nextPermutation(Set16 &set)
{
assert(Set16::size > 2);
uint i = Set16::size - 1;
for (;;) {
uint i1 = i, i2;
if (set.elem(--i) < set.elem(i1)) {
i2 = Set16::size;
while (set.elem(i) >= set.elem(--i2));
set.swap(i, i2);
set.reverse(i1, Set16::size);
return true;
}
if (!i) {
set.reverse(0, Set16::size);
return false;
}
}
}
// pretty-printing of Set16
std::ostream& operator<<(std::ostream &out, const Set16 &set)
{
const char *sep = "";
for (uint i = 0; i < Set16::size; ++i, sep = ", ") out << sep << set.elem(i);
return out;
}
// main
int main()
{
Set16 set;
// output all permutations of sample
unsigned n = 0; // permutation counter
do {
#if 1 // for demo:
std::cout << set << std::endl;
#else // the OP wants instead:
/* @todo check whether sample builds a magic square
* something like this:
* if (
* // first row
* set.elem(0) + set.elem(1) + set.elem(2) == 15
* etc.
*/
#endif // 1
++n;
} while(nextPermutation(set));
std::cout << n << " permutations found." << std::endl;
// done
return 0;
}
输出:
1, 2, 3
1, 3, 2
2, 1, 3
2, 3, 1
3, 1, 2
3, 2, 1
6 permutations found.
所以,我在这里:排列没有数组。
最后,另一个想法打击了我。可能是,任务的目的是教导“从外面看”......这可能值得再次研究Magic Squares的描述:
等效魔方
任何魔术方块都可以旋转和反射,以产生8个平凡的不同方块。在魔方理论中,所有这些都被认为是等价的,据说八个这样的方格组成一个等价类。
给定订单的幻方数
不包括旋转和反射,只有一个3×3魔方......
但是,我不知道如何将其与按升序排序解决方案的要求结合起来。