我参加了一个狂欢节,在每个地方,他们用特殊的打孔标记你的节目。打孔器是3x3空间的网格。在每个空间中,有一个针刺穿你的纸张或没有。这让我想知道你可以使用这个工具制作多少种不同的模式。我的第一个想法是:2 ^ 9 = 512,但是所有9个空间都是无针的并不是真正的一拳,所以真的:511。
然后复杂性打击了我。特别是因为工人在打纸时并不是那么小心,所以这些看起来都很明显:
x.. .x. ... etc.
.x. x.. .x.
... ... ..x
问题:如何编写测试以考虑轮换和转移?
到目前为止的勤奋和思想:
重叠:
/ = the spaces in the new one to test
\ = the spaces in a verified unique one
1 2 25
/ / / . . . . . / / / . . . . . . . . . .
/ / / . . . . . / / / . . . . . . . . . .
/ / X \ \ . . . / X X \ . . . . \ \ \ . .
. . \ \ \ . . . . \ \ \ . . . . \ \ \ . .
. . \ \ \ . . . . \ \ \ . . . . \ \ X / /
. . . . . . . . . . . . . . . . . . / / /
. . . . . . . . . . . . . . . . . . / / /
答案 0 :(得分:7)
我们只需要考虑第一行和第一列中有冲压的模式。如果第一行为空,则可以向上移动模式。如果第一列为空,则可以向左移动图案。在任何一种情况下,我们都可以得到一个类似的模式,我们会考虑。
对于这些模式,我们需要检查旋转的版本是否相同。我们通过应用最多三个90度旋转来实现这一点,可能向左移动以移除前导空列(第一行永远不会为空)并找到具有最低数值的模式。
然后我们可以将此值添加到哈希集中,该哈希集只保留唯一值。
不包括空模式,因为它的所有行都是空的。
为了实现这一点,我们将模式编码为连续位:
012
345
678
我们需要的操作大多非常简单:
Test for an empty row: (n & 7) == 0 // bits 0,1,2 not set
Test for an empty column: (n & 73) == 0 // bits 0,3,6 not set
Shift pattern up: n -> (n >> 3)
Shift pattern left: n -> (n >> 1)
最棘手的部分是旋转,它实际上只是重新排列所有位:
n -> ((n & 1) << 2) + ((n & 2) << 4) + ((n & 4) << 6)
+ ((n & 8) >> 2) + (n & 16) + ((n & 32) << 2)
+ ((n & 64) >> 6) + ((n & 128) >> 4) + ((n & 256) >> 2);
在C#中:
public static int Count3x3() {
HashSet<int> patterns = new HashSet<int>();
for (int i = 0; i < 512; i++) {
if ((i & 7) == 0 || (i & 73) == 0)
continue;
int nLowest = i;
int n = i;
do {
nLowest = Math.Min(nLowest, n);
n = ((n & 1) << 2) + ((n & 2) << 4) + ((n & 4) << 6)
+ ((n & 8) >> 2) + (n & 16) + ((n & 32) << 2)
+ ((n & 64) >> 6) + ((n & 128) >> 4) + ((n & 256) >> 2);
while ((n & 73) == 0)
n >>= 1;
} while (n != i);
patterns.Add(nLowest);
}
return patterns.Count;
}
此函数返回116.我的机器所用时间为0.023毫秒。
编辑:使用4次观察可以获得额外7倍的提升:
因此,如果我们应用这些观察并展开内部do循环,我们得到以下结果:
static int Rotate(int n) {
n = ((n & (1+32)) << 2) + ((n & 2) << 4) + ((n & 4) << 6)
+ ((n & (8+256)) >> 2) + (n & 16)
+ ((n & 64) >> 6) + ((n & 128) >> 4);
while ((n & 73) == 0)
n >>= 1;
return n;
}
public static int Count3x3_3() {
bool[] visited = new bool[512];
int count = 0, r;
for (int i = 0; i < 512; i++) {
if (visited[i])
continue;
if ((i & 7) == 0 || (i & 73) == 0)
continue;
count++;
if ((r = Rotate(i)) == i) continue;
visited[r] = true;
if ((r = Rotate(r)) == i) continue;
visited[r] = true;
visited[Rotate(r)] = true;
}
return count;
}
在同一台机器上运行大约3μs。
答案 1 :(得分:3)
我的解决方案:116种独特的形状
当测试2个形状是否相等时,比较引脚数可以节省大量时间。但我最大的突破是意识到所有这25个位置都可以被这个替换:要检查两个3x3形状中的每一个是否相等,用两个零连接线,然后修剪前导零和尾随零。 concat零是为了防止环绕。例如:
010 => 01000 => 0100010100000 => 1000101
101 10100
000 000
000 => 00000 => 0000001000101 => 1000101
010 01000
101 101
然后只测试结果是否相等。这是4个简单的迭代(每个旋转1个)而不是100个(25个位置* 4个旋转)更复杂的迭代。
时间:
仅字符串:
OOP和更好的缓存:17毫秒
答案 2 :(得分:1)
首先,除了翻译之外,我们可以查看两个相同的旋转,作为彼此的旋转。想象一下,打孔图案位于球体表面上:我们可以通过沿着水平轴和垂直轴旋转球体来“平移”它(就像它握在我们手中一样。)
我们在这里沿着第三个剩余轴旋转我们的球体,也可以捕获两个相当于旋转的冲头(如90度转弯)。
现在我们已经将问题简化为“球体表面有多少独特的打孔图案,直到旋转?”对于像这样对称的唯一对象进行计数,您需要not-Burnside's Lemma。 This book是一本很好的入门书。
答案 3 :(得分:1)
我认为这不像球体情况,因为你不能围绕边缘旋转? IE:
XOO
XXO
XOO
与
不同OOX
XOX
OOX
我试着在纸上手工计数,看看我得到了什么。考虑2x2情况 - 你有1个0点,1个有1个点,2个有2个点(相邻或对角线),1个有3个点,1个有4个;总共5个(如果忽略空的情况,则为4个)。请注意,枚举是对称的,因为将空白计为完全空格是相同的。对于3x3的情况,我得到了这个:
C(0) = 1
C(1) = 1
C(2) = 5
C(3) = 10
C(4) = 21
然后通过对称性,21,10,5,1,1
我得到了76.我很容易错位,特别是在4/5的情况下。
我能想到自动枚举这些的唯一方法是移动和旋转模式以查看它们是否与先前列举的模式相匹配。移动是棘手的,因为你只能移动直到你“碰撞”边缘。
答案 4 :(得分:1)
值得指出的是,如果你真的需要每个形状“看起来”独特,无论它如何旋转或移动,你都很少有选择。例如,单个打孔,无论它在网格中的哪个位置,都将始终看起来相同。此外,假设方形网格和圆形销,并假设较小的间距差异(√2)是微不足道的,那么连续2个对角线的孔将看起来与两个相邻的销钉相同,因为所有观察者看到的是靠近的两个孔。同样,对角线中的3个看起来就像直线上的3个,这极大地限制了您的选择。
请注意,形状可能比我们之后的组合更好,因为我们不关心实际组合是什么,只是结果是什么形状在纸上。
我认为我们可以假定无论形状如何,它都可以旋转和移动,使得左上方的针被打孔(特别是如果允许在45度上旋转),这使我们能够缩小搜索范围更深入。我们使用以下规则来实现这一目标:
我做了一个非常快速的纸笔蛮力搜索可能的形状,看起来可行选项的列表非常小,你可以在几分钟内将它们全部列出。
答案 5 :(得分:1)
您不是要求计算转换和旋转之前的唯一模式的数量,而是要求进行一致性测试。
选择3x3网格的位串表示。我会逐行选择,自上而下。通过设置相应孔被打孔的位,我们现在可以将9位整数映射到打孔模式(反之亦然。)
对于任何特定的表示,我们可以设计代表旋转和翻译的比特操作。有些翻译在某些模式上是非法的,因为我们希望避免“缠绕”。
正如轮换和翻译是可逆的一样,我们的运营也是如此。如果两个动作将模式A映射到B,然后映射到B到C,我们当然可以组成动作来进行转换,将A转换为C.不执行任何操作(身份转换)也是合法的,因此我们可以从A.可达性到达A.因此,通过变换是打孔模式的等价关系,因此等效模式对空间进行划分。
有一种为每个打孔模式分配正整数分数的方法,我们可以调用有序的原则:包含模式的等价类将包含最低分数的唯一模式(包括翻译和旋转)。我们将选择这种最小模式作为等价类的代表。如果两个模式具有相同的等价类代表,则它们必然是一致的。如果他们不这样做,他们必然不一致。
鉴于一种模式,我们如何找到其最小权重代表?通过检查,贪婪的算法不能保证工作。我们可以找到一个无数的启发式优化算法,或者我们可以注意到我们只推了9位并且穷尽地搜索空间。应该注意的是,出于同样的原因,这很好地计算了一次,并且永远地在查找表中推送。
这是详尽的搜索。注意适当的缓存它仍然很快(不到一秒钟。)
#!/usr/bin/env ruby
require 'set'
class PunchPattern < String
@@representatives = Hash.new do |h, k|
equivalence_class = k.closure
representative = equivalence_class.min
k.closure.each do |node|
h[node] = representative
end
representative
end
def initialize(s)
raise "9 digits of 0 and 1, pls" unless s =~ /[01]{9}/
super
end
def left
return nil unless self =~ /0..0..0../
PunchPattern.new([self[1...3], 0, self[4...6], 0, self[7...9], 0].join)
end
def right
return nil unless self =~ /..0..0..0/
PunchPattern.new([0, self[0...2], 0, self[3...5], 0, self[6...8]].join)
end
def up
return nil unless self =~ /000....../
PunchPattern.new([self[3...9], 0, 0, 0].join)
end
def down
return nil unless self =~ /......000/
PunchPattern.new([0, 0, 0, self[0...6]].join)
end
def turn
PunchPattern.new([2, 5, 8, 1, 4, 7, 0, 3, 6].collect { |i| self[i].chr }.join)
end
def closure
seen = Set.new([])
frontier = Set.new([self])
until frontier.empty?
node = frontier.first
frontier.delete(node)
seen.add(node)
%w{left right up down turn}.collect do |motion|
node.send motion
end.compact.each do |neighbor|
frontier.add(neighbor) unless seen.include? neighbor
end
end
seen
end
def representative
self.class.representatives[self]
end
def self.representatives
@@representatives
end
end
(0...512).collect do |p|
p = PunchPattern.new(p.to_s(2).rjust(9, '0'))
[p.representative, p]
end.inject(Hash.new { |h, k| h[k] = [] }) do |h, pair|
h[pair.first] << pair.last
h
end.sort_by { |pair| pair.first }.each do |representative, patterns|
puts patterns.collect { |p| p[0...3] + " " }.join
puts patterns.collect { |p| p[3...6] + " " }.join
puts patterns.collect { |p| p[6...9] + " " }.join
puts
end
puts "#{PunchPattern.representatives.values.uniq.size} total congruence classes"
可生产
$ ./congruence.rb
000
000
000
000 000 000 000 000 000 001 010 100
000 000 000 001 010 100 000 000 000
001 010 100 000 000 000 000 000 000
000 000 000 000 000 000 000 001 010 011 100 110
000 000 001 010 011 100 110 001 010 000 100 000
011 110 001 010 000 100 000 000 000 000 000 000
000 000 001 010 100 101
000 101 000 000 000 000
101 000 001 010 100 000
000 000 001 010 100 111
000 111 001 010 100 000
111 000 001 010 100 000
000 000 000 000 001 010 010 100
001 010 010 100 010 001 100 010
010 001 100 010 000 000 000 000
000 000 000 000 000 000 000 000 001 010 010 011 011 100 110 110
001 010 010 011 011 100 110 110 011 011 110 001 010 110 010 100
011 011 110 001 010 110 010 100 000 000 000 000 000 000 000 000
000 001 010 100
001 100 000 000
100 000 001 010
000 000 001 010 011 100 101 110
001 101 101 000 000 000 100 000
101 100 000 011 001 110 000 010
000 000 001 010 010 011 100 100
001 011 110 001 010 100 010 100
110 100 000 001 001 000 010 010
000 000 001 010 011 100 110 111
001 111 111 010 001 100 010 100
111 100 000 011 001 110 010 000
000 000 001 010 010 010 100 101
010 101 010 001 100 101 010 010
101 010 001 010 010 000 100 000
000 000 001 010 010 010 100 111
010 111 011 011 110 111 110 010
111 010 001 010 010 000 100 000
000 000 011 110
011 110 011 110
011 110 000 000
000 000 010 011 011 100 101 110
011 101 001 010 101 010 110 100
101 110 011 001 000 110 000 010
000 010 011 100
011 011 110 110
110 001 000 010
000 000 010 011 011 100 110 111
011 111 011 011 111 110 110 110
111 110 011 001 000 110 010 000
000 001 010 100
100 000 000 001
001 010 100 000
000 000 001 001 010 010 100 110
100 110 001 010 010 100 011 001
011 001 010 010 100 100 000 000
000 000 001 010 011 100 101 110
100 101 000 000 000 101 001 000
101 001 011 110 010 000 000 100
000 000 001 010 011 100 110 111
100 111 001 010 010 111 100 001
111 001 011 110 010 000 100 000
000 000 001 010 011 101 110 110
101 110 010 100 001 011 010 101
011 101 011 110 010 000 100 000
000 011 101 110
101 000 101 000
101 011 000 110
000 000 011 011 101 110 110 111
101 111 001 010 111 010 100 101
111 101 011 011 000 110 110 000
000 001 010 110
110 011 110 011
011 010 100 000
000 000 001 010 011 110 110 111
110 111 011 110 011 110 111 011
111 011 011 110 010 100 000 000
000 011 110 111
111 011 110 111
111 011 110 000
001 100
000 000
100 001
001 100 101 101
000 000 000 000
101 101 001 100
001 011 100 100
000 000 001 100
110 100 001 001
001 100 101 111
000 100 001 000
111 101 001 100
001 001 100 110
001 100 000 000
100 100 011 001
001 100 101 111
001 000 100 000
101 111 100 001
001 011 100 110
001 100 100 001
110 100 011 001
001 100 111 111
001 100 001 100
111 111 001 100
001 100
010 010
100 001
001 100 101 101
010 010 010 010
101 101 001 100
001 011 100 100
010 010 011 110
110 100 001 001
001 100 101 111
010 110 011 010
111 101 001 100
001 001 100 110
011 110 010 010
100 100 011 001
001 100 101 111
011 010 110 010
101 111 100 001
001 011 100 110
011 110 110 011
110 100 011 001
001 100 111 111
011 110 011 110
111 111 001 100
001 010 100 101
100 000 001 000
001 101 100 010
001 010 010 100
100 001 100 001
010 100 001 010
001 010 101 110
100 100 001 001
011 101 010 100
001 101 101 110
100 000 001 000
101 011 100 101
001 011 100 110
100 001 001 100
110 100 011 001
001 101 110 111
100 001 100 001
111 011 101 100
001 010 100 111
101 000 101 000
001 111 100 010
001 010 010 110
101 100 101 001
010 011 100 010
001 010 110 111
101 100 101 001
011 111 100 010
001 110
101 000
100 011
001 101 110 111
101 101 000 000
101 100 111 011
001 011 110 110
101 101 001 100
110 100 011 011
001 110 111 111
101 100 001 101
111 111 011 100
001 010 100 101
110 010 011 010
001 101 100 010
001 010 010 100
110 011 110 011
010 100 001 010
001 010 101 110
110 110 011 011
011 101 010 100
001 101 101 110
110 010 011 010
101 011 100 101
001 011 100 110
110 011 011 110
110 100 011 001
001 101 110 111
110 011 110 011
111 011 101 100
001 010 100 111
111 010 111 010
001 111 100 010
001 010 010 110
111 110 111 011
010 011 100 010
001 010 110 111
111 110 111 011
011 111 100 010
001 110
111 010
100 011
001 101 110 111
111 111 010 010
101 100 111 011
001 011 110 110
111 111 011 110
110 100 011 011
001 110 111 111
111 110 011 111
111 111 011 100
010 011 100 101
001 100 001 100
101 001 110 010
010 010 011 100
001 101 100 101
110 001 010 010
010 011 100 111
001 101 101 100
111 001 110 010
010 011 100 101
011 110 011 110
101 001 110 010
010 010 011 100
011 111 110 111
110 001 010 010
010 011 100 111
011 111 111 110
111 001 110 010
010
101
010
010 010 011 110
101 101 101 101
011 110 010 010
010 011 101 110
101 100 101 001
101 011 010 110
010 011 110 111
101 101 101 101
111 011 110 010
010
111
010
010 010 011 110
111 111 111 111
011 110 010 010
010 011 101 110
111 110 111 011
101 011 010 110
010 011 110 111
111 111 111 111
111 011 110 010
011 100 101 101
000 001 000 100
101 101 110 001
011 100
000 101
110 001
011 100 101 111
000 101 101 000
111 101 001 110
011 100 101 111
001 001 100 100
101 111 110 001
011 011 100 110
001 100 101 101
110 110 011 001
011 100 111 111
001 101 100 101
111 111 110 001
011 100 101 101
010 011 010 110
101 101 110 001
011 100
010 111
110 001
011 100 101 111
010 111 111 010
111 101 001 110
011 100 101 111
011 011 110 110
101 111 110 001
011 011 100 110
011 110 111 111
110 110 011 001
011 100 111 111
011 111 110 111
111 111 110 001
011 101 101 110
100 001 100 001
101 110 011 101
011 101 110 111
100 101 101 001
111 011 101 110
011 101 110 111
101 101 001 100
101 110 111 011
011 110
101 101
110 011
011 110 111 111
101 101 101 101
111 111 011 110
011 101 101 110
110 011 110 011
101 110 011 101
011 101 110 111
110 111 111 011
111 011 101 110
011 101 110 111
111 111 011 110
101 110 111 011
011 110
111 111
110 011
011 110 111 111
111 111 111 111
111 111 011 110
101
000
101
101 101 101 111
000 001 100 000
111 101 101 101
101 101 111 111
001 100 001 100
111 111 101 101
101
010
101
101 101 101 111
010 011 110 010
111 101 101 101
101 101 111 111
011 110 011 110
111 111 101 101
101 111
101 000
101 111
101 111 111 111
101 001 100 101
111 111 111 101
101 111
111 010
101 111
101 111 111 111
111 011 110 111
111 111 111 101
111
101
111
111
111
111
117 total congruence classes
..为117个班级。
答案 6 :(得分:0)
我不明白这部分是关于轮换的,但对于这种情况:
有3x3 = 9个洞和10个案例,每次只能发生一个案例:
Case 1 = no holes
Case 2 = one hole
...
Case 10 = 9 holes
然后使用组合公式C(n,k):
总计= C(9,0)+ C(9,1)+ ...... + C(9,9)
这是对n个元素的不同组合求和。
Totol = 1 + 9 + 36 + 84 + 126 + 126 + 84 + 36 + 9 + 1 = 512
我认为你是对的,512似乎是正确的,理论上无针的定义也是一个组合,如果你不想要它只是删除它得到511.
所有这些情况都是单独发生的,因此我们添加了不同的案例。
如果它们是同步发生的,例如计算3名雇员冲压纸张的组合或计算一个雇员3次标记纸张的组合,那么它会变得更复杂,应该是512 * 512 * 512 nxm规则。
简单显示中的m * n规则是:
我有4个口袋,两个= n手:
my_left * 4(口袋)= 4 my_right * 4(口袋)= 4
总= 4 + 4 = 4 * 2 = m * n
一次只有一只手可以进入口袋,或者只有一名雇员的一个组合只与另一名雇员的一个组合配对,这就是我们采用m * n规则的确切原因。
这就是我的想法,我不是数学家,也不是100%正确的说法,这正是我从概率课程中记得的。
我并不认为100%正确,这是我记得的概率课程。
至于模式重叠,检查模式是否已经找到等我根本不会打扰,因为伪代码中存在如此多的生成组合的算法。因为它们生成然后不需要检查重叠或任何东西。
毕竟这就是generat意味着它是先验设计找到所有结果,让它运行。
我曾经发现一种比简单组合更难得的算法,当我把它变成php时,它完美地完成了工作,无需担心重叠或任何事情。