计数排列 - 将计数器存储在数组中

时间:2016-08-08 17:13:08

标签: c arrays algorithm onlinejudge

输入: 我有一些数组,如:

1, 2, 3, 4, 5
2, 1, 3, 4, 5
3, 2, 5, 4, 1
5, 4, 3, 1, 2
.....

所有这些都是5位数的非重复排列 - 5C5。行可以重复,但行中的任何数字都是唯一的。

目的: 计算输入数据中每种类型(排列)的数组数量。

我的想法: 5C5表示只有120个唯一行。所以我可以在int[120]数组中存储计数器。并在阅读输入时递增它们。

我的问题: 是否有任何有效的算法将此数组转换(哈希)到数组索引?

优先语言是C,带有指针和手动内存管理。在完美的情况下,我尝试做类似的事情:

FILE *f;
int counters[120] = {0};
char seq[20];
parse_line(f, seq); #scans and parses string into array
counters[hash(seq)]++;

PS: 通过解决" UVa 157 - Recycling",我对这个问题的启发。后来我看到了解决方案并理解我误解了任务,但问题没有得到解答。

2 个答案:

答案 0 :(得分:5)

进行基本转换。第一个数字位于基数5,第二个数字位于基数4,然后是基数3和基数2.因此,例如:

1, 2, 3, 4, 5 -> 0 * 4*3*2*1 + 0 * 3*2*1 + 0 * 2*1 + 0 * 1 ->   0
2, 1, 3, 4, 5 -> 1 * 4*3*2*1 + 0 * 3*2*1 + 0 * 2*1 + 0 * 1 ->  24
3, 2, 5, 4, 1 -> 2 * 4*3*2*1 + 1 * 3*2*1 + 2 * 2*1 + 1 * 1 ->  59
5, 4, 3, 1, 2 -> 4 * 4*3*2*1 + 3 * 3*2*1 + 2 * 2*1 + 0 * 1 -> 118
5, 4, 3, 2, 1 -> 4 * 4*3*2*1 + 3 * 3*2*1 + 2 * 2*1 + 1 * 1 -> 119

请记住,只计算您在选择数字时未见过的数字!小心翼翼地走过上面的第三排:

3, 2, 5, 4, 1

首先,我们将数字映射到数字:

1 2 3 4 5
0 1 2 3 4

由于第一个数字为3,因此第一个数字为2。现在我们从数字中删除3,给出

1 2 4 5
0 1 2 3

下一个数字是2,因此下一个数字是1。映射现在是

1 4 5
0 1 2

下一个数字是5,因此下一个数字是2。映射现在是

1 4
0 1

下一个数字是4,因此下一个数字是1。最后一位数字将为0,但它不会对总和作出任何贡献 - 最后一位数字是一元数字,因此它始终为0。因此,数字32541对应于数字21210

要计算基数为10的这个数字的值,我们使用通常的基本转换例程:我们将"列值乘以"通过当前列的基数,然后添加当前数字的值乘以列值。所以:

  0 * 1
+ 1 * (1*1)
+ 2 * (2*1*1)
+ 1 * (3*2*1*1)
+ 2 * (4*3*2*1*1)
-----------------
 59

另请参阅factorial number systems上的维基百科页面。

答案 1 :(得分:1)

最简单但内存消耗的解决方案是创建非冲突哈希。将数组转换为数字,假设排列仅包含5位数。数字的最大值只能是54321.取A[54321],从数字和增量计数器计算数字。

理论上,最佳无碰撞散列具有以下表达式:
如果S = s 0 s 1 s 2 ... s n-1
散列(S)= s 0 * M 0 + s 1 * M 1 + s 2 * M 3 ... s n-1 * M n-1
其中M是s i 可以采用的数字集的大小。

在你的情况下,M是5,n是5,
因此,哈希的最大值需要为
1 * 5 0 + 2 * 5 1 + 3 * 5 2 + 4 * 5 3 + 5 * 5 4 = 3711。