import random
def sample(times,n):
count = 0;
for i in range(times):
count += p(n)
return count*1.0/times;
def p(n):
perm = range(n);
for i in range(n):
a = random.randrange(n)
b = random.randrange(n)
perm[a],perm[b]=perm[b],perm[a];
return perm==range(n)
print sample(500000,5)
下面是 C 代码,用于计算兰德可以产生并计算概率的2N- 元组指数的值的数目。从 N = 0开始,它显示计数为1、1、8、135、4480、189125和12450816,概率分别为1、1、 .5、 .185185、 .0683594、 .0193664和.00571983。计数不会出现在 整数序列百科全书中,所以要么我的程序有一个错误,要么这是一个非常模糊的问题。如果是这样的话,这个问题并不是要求求职者去解决,而是要揭露他们的一些思维过程,以及他们如何处理挫折感。我不认为这是一个好的面试问题。
#include <inttypes.h>
#include <math.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#define swap(a, b) do { int t = (a); (a) = (b); (b) = t; } while (0)
static uint64_t count(int n)
{
// Initialize count of how many times the original order is the result.
uint64_t c = 0;
// Allocate space for selectors and initialize them to zero.
int *r = calloc(2*n, sizeof *r);
// Allocate space for array to be swapped.
int *A = malloc(n * sizeof *A);
if (!A || !r)
{
fprintf(stderr, "Out of memory.\n");
exit(EXIT_FAILURE);
}
// Iterate through all values of selectors.
while (1)
{
// Initialize A to show original order.
for (int i = 0; i < n; ++i)
A[i] = i;
// Test current selector values by executing the swap sequence.
for (int i = 0; i < 2*n; i += 2)
{
int m = r[i+0];
int n = r[i+1];
swap(A[m], A[n]);
}
// If array is in original order, increment counter.
++c; // Assume all elements are in place.
for (int i = 0; i < n; ++i)
if (A[i] != i)
{
// If any element is out of place, cancel assumption and exit.
--c;
break;
}
// Increment the selectors, odometer style.
int i;
for (i = 0; i < 2*n; ++i)
// Stop when a selector increases without wrapping.
if (++r[i] < n)
break;
else
// Wrap this selector to zero and continue.
r[i] = 0;
// Exit the routine when the last selector wraps.
if (2*n <= i)
{
free(A);
free(r);
return c;
}
}
}
int main(void)
{
for (int n = 0; n < 7; ++n)
{
uint64_t c = count(n);
printf("N = %d: %" PRId64 " times, %g probabilty.\n",
n, c, c/pow(n, 2*n));
}
return 0;
}
Given our input [0, 1, 2].
Swap (0 1) and get [1, 0, 2].
Swap (1 1) and get [1, 0, 2]. ** Here is an identity **
Swap (2 2) and get [1, 0, 2]. ** And another **
如果群论在这里有一个应用的结果,那就太酷了——也许真的有!它肯定有助于完全消除所有这些乏味的计数(并将问题缩短到更优雅的程度)。我不在 N = 4工作了。对于 N > 5,给出的只是一个近似值(我不确定有多好)。如果您仔细想想,就会非常清楚为什么会这样: 例如,给定 N = 8换位,有明显的方法可以用上面没有考虑到的 四独特元素来创建身份。随着排列变得越来越长(据我所知...) ,方法的数量似乎越来越难以计算。
基元 int 数组上发生随机交换。在 java 方法中,参数总是通过值传递,所以在交换方法中发生的事情并不重要,因为数组的[ m ]和[ n ]元素(从下面的代码交换([ m ] ,a [ n ])传递的不是完整的数组。
答案是数组将保持不变。尽管有上面提到的条件。参见下面的 java 代码示例:
import java.util.Random;
public class ArrayTrick {
int a[] = new int[10];
Random random = new Random();
public void swap(int i, int j) {
int temp = i;
i = j;
j = temp;
}
public void fillArray() {
System.out.println("Filling array: ");
for (int index = 0; index < a.length; index++) {
a[index] = random.nextInt(a.length);
}
}
public void swapArray() {
System.out.println("Swapping array: ");
for (int index = 0; index < a.length; index++) {
int m = random.nextInt(a.length);
int n = random.nextInt(a.length);
swap(a[m], a[n]);
}
}
public void printArray() {
System.out.println("Printing array: ");
for (int index = 0; index < a.length; index++) {
System.out.print(" " + a[index]);
}
System.out.println();
}
public static void main(String[] args) {
ArrayTrick at = new ArrayTrick();
at.fillArray();
at.printArray();
at.swapArray();
at.printArray();
}
}
Explanation for P2:
We want to calculate the probability that after 2 iterations, the array with
N elements won't change. We have 2 options :
- in the 2 iteration we got m == n (Probability of 1/N)
- in the 2 iteration we got m != n (Probability of N-1/N)
If m == n, we need that the array will remain after the 1 iteration = P1.
If m != n, we need that in the 1 iteration to choose the same n and m
(order is not important). So we get 2/N^2.
Because those events are independent we get - P2 = (1/N)*P1 + (N-1/N)*(2/N^2).
Pk = (1/N) * Pk-1 + (N-1/N) * X (第一个表示 m = = n,第二个表示 m! = n)
我得多想想 X 等于什么。(X 只是实公式的替代物,不是常数或其他任何东西)
Example for N = 2.
All possible swaps:
(1 1 | 1 1),(1 1 | 1 2),(1 1 | 2 1),(1 1 | 2 2),(1 2 | 1 1),(1 2 | 1 2)
(1 2 | 2 1),(1 2 | 2 2),(2 1 | 1 1),(2 1 | 1 2),(2 1 | 2 1),(2 1 | 2 2)
(2 2 | 1 1),(2 2 | 1 2),(2 2 | 2 1),(2 1 | 1 1).
Total = 16. Exactly 8 of them remain the array the same.
Thus, for N = 2, the answer is 1/2.
编辑:
我想介绍另一种方法:
我们可以将互换分为三类: 建设性互换、破坏性互换和无害互换。
建设性掉期是指使至少一个元素移动到正确位置的掉期。
破坏性掉期被定义为使至少一个元素从其正确位置移动的掉期。
无害互换是指不属于其他群体的互换。
很容易看出,这是所有可能的交换的分区。
现在我要证明的是:
The array will remain the same if and only if
the number of Destructive swap == Constructive swap in the iterations.
如果有人有反例,请写下来作为评论。
如果这个声明是正确的,我们可以采取所有的组合,并求和-
0个无害掉期,1个无害掉期,... N 个无害掉期。
对于每个可能的 k 无害交换,我们检查 N-k 是否为偶数,如果不是,我们跳过。如果是,我们把(N-k)/2表示为破坏性的,把(N-k)表示为建设性的。看看所有的可能性。
C B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B B
状态转换概率
在算法的每个步骤中,A的状态要么保持不变,要么从这些排列中的一个转换到另一个。我们现在感兴趣的是这些状态变化的可能性。让我们称 Pr (< em > i → < em > j )为状态在一个循环迭代中从排列 我变为排列 J的概率。
例如,我们可以利用这样一个事实,即 P的任意幂的所有对角线元素都是相等的。假设我们可以很容易地计算出 P< em > N 的踪迹,那么解决方案就是 tr (P< em > N )/N!.P< em > N 的迹等于其特征值的 N次方之和。因此,如果我们有一个有效的算法来计算 P的特征值,我们将被设置。然而,除了计算到 N = 5的特征值之外,我还没有进一步探讨这个问题。
C # 中的简单实现。
其思想是创建初始数组的所有可能的排列并枚举它们。
然后我们建立一个可能的状态变化矩阵。将矩阵本身乘以 N 次,我们将得到一个矩阵,它显示了从置换 # i 到置换 # j 在 N 个步骤中有多少种方式存在。Elemet [0,0]将显示有多少种方式会导致相同的初始状态。行 # 0的元素之和将显示不同方式的总数。通过将前者除以后者,我们得到了概率。
实际上排列的总数是 N ^ (2N)。
Output:
For N=1 probability is 1 (1 / 1)
For N=2 probability is 0.5 (8 / 16)
For N=3 probability is 0.1851851851851851851851851852 (135 / 729)
For N=4 probability is 0.068359375 (4480 / 65536)
For N=5 probability is 0.0193664 (189125 / 9765625)
For N=6 probability is 0.0057198259072973293366526105 (12450816 / 2176782336)
class Program
{
static void Main(string[] args)
{
for (int i = 1; i < 7; i++)
{
MainClass mc = new MainClass(i);
mc.Run();
}
}
}
class MainClass
{
int N;
int M;
List<int> comb;
List<int> lastItemIdx;
public List<List<int>> combinations;
int[,] matrix;
public MainClass(int n)
{
N = n;
comb = new List<int>();
lastItemIdx = new List<int>();
for (int i = 0; i < n; i++)
{
comb.Add(-1);
lastItemIdx.Add(-1);
}
combinations = new List<List<int>>();
}
public void Run()
{
GenerateAllCombinations();
GenerateMatrix();
int[,] m2 = matrix;
for (int i = 0; i < N - 1; i++)
{
m2 = Multiply(m2, matrix);
}
decimal same = m2[0, 0];
decimal total = 0;
for (int i = 0; i < M; i++)
{
total += m2[0, i];
}
Console.WriteLine("For N={0} probability is {1} ({2} / {3})", N, same / total, same, total);
}
private int[,] Multiply(int[,] m2, int[,] m1)
{
int[,] ret = new int[M, M];
for (int ii = 0; ii < M; ii++)
{
for (int jj = 0; jj < M; jj++)
{
int sum = 0;
for (int k = 0; k < M; k++)
{
sum += m2[ii, k] * m1[k, jj];
}
ret[ii, jj] = sum;
}
}
return ret;
}
private void GenerateMatrix()
{
M = combinations.Count;
matrix = new int[M, M];
for (int i = 0; i < M; i++)
{
matrix[i, i] = N;
for (int j = i + 1; j < M; j++)
{
if (2 == Difference(i, j))
{
matrix[i, j] = 2;
matrix[j, i] = 2;
}
else
{
matrix[i, j] = 0;
}
}
}
}
private int Difference(int x, int y)
{
int ret = 0;
for (int i = 0; i < N; i++)
{
if (combinations[x][i] != combinations[y][i])
{
ret++;
}
if (ret > 2)
{
return int.MaxValue;
}
}
return ret;
}
private void GenerateAllCombinations()
{
int placeAt = 0;
bool doRun = true;
while (doRun)
{
doRun = false;
bool created = false;
for (int i = placeAt; i < N; i++)
{
for (int j = lastItemIdx[i] + 1; j < N; j++)
{
lastItemIdx[i] = j; // remember the test
if (comb.Contains(j))
{
continue; // tail items should be nulled && their lastItemIdx set to -1
}
// success
placeAt = i;
comb[i] = j;
created = true;
break;
}
if (comb[i] == -1)
{
created = false;
break;
}
}
if (created)
{
combinations.Add(new List<int>(comb));
}
// rollback
bool canGenerate = false;
for (int k = placeAt + 1; k < N; k++)
{
lastItemIdx[k] = -1;
}
for (int k = placeAt; k >= 0; k--)
{
placeAt = k;
comb[k] = -1;
if (lastItemIdx[k] == N - 1)
{
lastItemIdx[k] = -1;
continue;
}
canGenerate = true;
break;
}
doRun = canGenerate;
}
}
}