“K变换”的排列

时间:2011-08-25 21:25:37

标签: algorithm math complexity-theory permutation

我几天来一直在反对这个问题,并在网上搜索有关如何解决它的任何提示。如果您喜欢以数学为导向的编程问题,请查看!

以下是problem (PDF courtesy of UVA)

  

考虑一系列n个整数< 1 2 3 4 ... n>。由于所有值都是不同的,我们知道有n个阶乘排列。如果原始位置和每个元素的新位置之间的绝对差值最多为K,则置换被称为K变换。给定n和K,您必须找出K变换排列的总数。

...

  

输入:    第一行输入是整数T(T <20),表示测试用例的数量。每个情况由包含两个整数n和K的行组成(1 <= n <= 10 ^ 9)和(0 <= K <= 3)。

     

输出:   对于每种情况,首先输出案例编号,然后输出所需的结果。由于结果可能很大,输出结果模73405。

问题制定者Sohel Hafiz将此问题归类为“Fast Matrix Exponentiation”。不幸的是,我在这里链接的谷歌搜索似乎没有显示任何相关的链接,除了维基百科页面厚的数学术语和符号(维基百科已经证明我是任何数学教科书的不良替代品)。

这是我到目前为止所做的:

此代码将通过递归计算n和k的低值的K变换排列的数量,但是太复杂。构建一个用于搜索模式的表格已经足够了:

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int permute(int * a, int size, int i, int k)
{
  int j;
  int total = 0;
  int x = size-i;
  int low=0;
  int high=size;
  if (i == 0)
  {
/*    for (j=0;j<size;j++)
      printf("%d, ", a[j]);
    printf("\n");
*/    return 1;
  }
  if (x-k>0)
    low = x-k;
  if (x+k+1<size)
    high = x+k+1;
  for (j=low;j<high;j++)
  {
    int b[size];
    memcpy(b,a,size*sizeof(int));
    if (b[j] == 0)
    {
      b[j] = x+1;
      total += permute(b,size,i-1,k);
    }
  }
  return total;
}

int main() 
{
  int n, k, j, y, z;
  int * arr;
  /*scanf("%d %d", &n,&k);*/ k=2;
  for (n=0;n<14;n++)
  {
    int empty[n];
    for (j=0;j<n;j++)
      empty[j] = 0;
    arr = empty;  
    z = permute(arr, n, n, k);
    y = magic(n,k);
    printf("%d %d\n",z, y);
  }
  return 0;
}

我发现的第一件事是k = 1显然是Fibonacci序列。 主要的神奇功能是我后来想到的,几乎是偶然的。它仅适用于k = 2,但精确到n = 14。

int magic(int n, int k)
{
  if (n<0)
    return 0;
  if (n==0)
    return 1;
  if (n==1)
    return 1;
  return 2*magic(n-1,k) + 2*magic(n-3,k) - magic(n-5,k);  
}

非常奇怪!我不知道这个函数的重要性,但它可以简化为在循环中运行,以便以足够快的速度运行以完成K = 2的值,最大值为10 ^ 9。

剩下的就是找到一个非递归方程,可以在合理的时间内(10s以下)找到K = 3的任何值。

编辑:我对用于在合理的时间内解决任何给定n和k的问题的算法感兴趣。我不希望任何人通过将代码写入比赛规则的规范来确认他们的算法是否正常工作,我在答案中寻找的是如何解决问题并应用数值方法来达成解决方案的描述。

2 个答案:

答案 0 :(得分:6)

问题分为两部分。首先是确定k=0, 1, 2, 3的递推公式。第二部分是使用递推公式计算大n的值。

第一部分:

p(n, k)n转化的k元素的排列数。 当k=0重复发生时只有p(n, 0) = 1

对于k=1,首先考虑排列中的1。它位于位置1或位置2.如果它位于位置1,则其余元素只是n-1元素的原始问题。所以我们有p(n, 1) = p(n-1, 1) + ...。如果第一个元素进入位置2,那么什么?在这种情况下,第二个元素必须进入位置1.此时,您有n-2个元素的原始问题。因此,重复是p(n, 1) = p(n-1, 1) + p(n-2, 1),这是Fibonacci序列。

对于k=2k=3,您获得的可能性更大,但推理是相同的。 [仍在制定确切的复发]

第二部分是计算大值n的重现的解决方案。为此,您将重复放入矩阵形式,并重复平方/乘法以获得矩阵的高次幂。对于k=1情况,矩阵为:

A = [0 1]
    [1 1]

要获得p(n + 2, 1),您需要计算A^n * [1, 1]

答案 1 :(得分:5)