Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/spring-mvc/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 按索引号获取具有指定度的置换_Python_Algorithm_Permutation_Time Complexity_Combinatorics - Fatal编程技术网

Python 按索引号获取具有指定度的置换

Python 按索引号获取具有指定度的置换,python,algorithm,permutation,time-complexity,combinatorics,Python,Algorithm,Permutation,Time Complexity,Combinatorics,我花了好几个小时研究这个问题,但还是没弄明白 将置换度定义为创建置换所需的最小置换数。所以a(0,1,2,3)的度数是0,(0,1,3,2)的度数是1,(1,0,3,2)的度数是2,以此类推 将空间Snd视为具有度d的长度序列n的所有排列的空间 我想要两个算法。一个在该空间中获取排列并为其分配索引号,另一个在Snd中获取项目的索引号并检索其排列。索引编号显然应该是连续的(即在0到len(Snd)-1的范围内,每个排列都有一个不同的索引编号。) 我希望这在O(理智)中实现;这意味着,如果你要求17

我花了好几个小时研究这个问题,但还是没弄明白

将置换度定义为创建置换所需的最小置换数。所以a
(0,1,2,3)
的度数是0,
(0,1,3,2)
的度数是1,
(1,0,3,2)
的度数是2,以此类推

将空间
Snd
视为具有度
d
的长度序列
n
的所有排列的空间


我想要两个算法。一个在该空间中获取排列并为其分配索引号,另一个在
Snd
中获取项目的索引号并检索其排列。索引编号显然应该是连续的(即在
0到len(Snd)-1的范围内,每个排列都有一个不同的索引编号。)

我希望这在
O(理智)
中实现;这意味着,如果你要求17号排列,算法不应该遍历0到16之间的所有排列来检索你的排列

你知道怎么解决这个问题吗

(如果要包含代码,我更喜欢Python,谢谢。)

更新:

我想要一个解决方案,其中

  • 排列是根据它们的字典顺序排序的(不是通过手动排序,而是通过一种有效的算法,该算法首先给出它们的字典顺序),并且
  • 我希望算法也能接受不同度数的序列,所以我可以说“我希望排列空间(5)中1、3或4度数的所有排列中有78个排列”。(基本上这个函数需要一个度元组。)这也会影响反向函数,该函数通过排列计算索引;根据度数的设置,指数会有所不同

  • 在过去的两天里,我试图解决这个问题,但没有成功。如果您可以提供Python代码,那就最好了。

    我认为您正在寻找一种变体,用于测量两个字符串之间的编辑次数。有效的计算方法是采用一种称为动态规划(dynamic programming)的技术——链接文章中提供了一种“正常”Levenshtein距离的伪算法。您需要对此进行调整,以考虑这样一个事实:不添加、删除或替换字符,唯一允许的操作是在两个位置交换元素


    关于你的第二个算法:在排列度和“a”结果排列之间不是1:1的关系,相反,可能的结果的数量随着交换的数量呈指数增长:对于
    k
    元素序列,有
    k*(k-1)/2
    可能的索引对可以交换。如果我们将该数字称为
    l
    ,在
    d
    交换之后,您就有了
    l^d
    可能的结果(即使其中一些可能是相同的,如先交换01然后交换23,或先交换23然后交换01).

    长度n和度数d的置换正是那些可以写成k=n-d循环组合的置换,这些循环将n个元素分割开来。这种排列的数量由n表示,写在方括号中k的顶部

    第一类斯特林数满足递推关系

    [n]           [n - 1]   [n - 1]
    [ ] = (n - 1) [     ] + [     ]
    [k]           [  k  ]   [k - 1],
    
    这意味着,直观地说,将n个元素划分为k个循环的方法是将n-1个非最大元素划分为k个循环,并以n-1种方法中的一种方法拼接到最大元素中,或者将最大元素放在其自己的循环中,并将n-1个非最大元素划分为k-1个循环。从一个重复值表开始工作,可以沿着这条线追踪决策

    memostirling1 = {(0, 0): 1}
    def stirling1(n, k):
        if (n, k) not in memostirling1:
            if not (1 <= k <= n): return 0
            memostirling1[(n, k)] = (n - 1) * stirling1(n - 1, k) + stirling1(n - 1, k - 1)
        return memostirling1[(n, k)]
    
    def unrank(n, d, i):
        k = n - d
        assert 0 <= i <= stirling1(n, k)
        if d == 0:
            return list(range(n))
        threshold = stirling1(n - 1, k - 1)
        if i < threshold:
            perm = unrank(n - 1, d, i)
            perm.append(n - 1)
        else:
            (q, r) = divmod(i - threshold, stirling1(n - 1, k))
            perm = unrank(n - 1, d - 1, r)
            perm.append(perm[q])
            perm[q] = n - 1
        return perm
    
    memostring1={(0,0):1}
    def斯特林1(n,k):
    如果(n,k)不在备忘录Stirling1中:
    
    如果不是(1我写了这个stackoverflow回答了一个类似的问题:。它能帮助我吗

    不同之处可能在于用于生成perm的交换位,但Python中给出了index to perm和perm to index函数

    我后来继续创建了这个Rosetta代码任务,该任务通过引用和更多代码来充实


    希望有帮助:-)

    这个答案不如我的另一个答案优雅/高效,但它描述了一个多项式时间算法,可以处理排列顺序的附加约束。我将描述一个子程序,给定一个n元素置换的前缀和一组度,计算有多少置换具有该前缀和属于该集合的度。给定此子例程,我们可以对指定子集中指定秩的排列进行n元搜索,每次将已知前缀扩展一个元素

    我们可以将n元素置换p可视化为一个n顶点,n弧有向图,其中,对于每个顶点v,有一个从v到p(v)的弧。这个有向图由一组顶点不相交的圈组成。例如,排列31024看起来像

     _______
    /       \
    \->2->0->3
     __     __
    /  |   /  |
    1<-/   4<-/ .
    
    2->0->3
     __
    /  |
    1<-/ .
    
    (ASCII art方括号),是阶数为n-k的n元素置换数。要计算n元素置换的r元素前缀的扩展数,计数c,前缀中的完整循环数。对于指定集合中的每个度d,斯特林数之和

    [  n - r  ]
    [         ]
    [n - d - c]
    
    第一类,将“不可能”指数的项设为零(一些受分析启发的斯特林数定义在意外的地方不为零)

    为了从排列中获得秩,我们再次进行n元搜索,但这次我们使用排列而不是秩来指导搜索

    下面是这两个方面的一些Python代码(包括一个测试函数)

    导入itertools
    记忆斯特林1={(0,0):1}
    def斯特林1(n,k):
    ans=记忆斯特林1.get((n,k))
    如果ans为无:
    
    如果不是1如果你完全在词汇方面工作,那么第一部分是直截了当的。给我答案
    [  n - r  ]
    [         ]
    [n - d - c]
    
    import itertools
    
    memostirling1 = {(0, 0): 1}
    def stirling1(n, k):
        ans = memostirling1.get((n, k))
        if ans is None:
            if not 1 <= k <= n: return 0
            ans = (n - 1) * stirling1(n - 1, k) + stirling1(n - 1, k - 1)
            memostirling1[(n, k)] = ans
        return ans
    
    def cyclecount(prefix):
        c = 0
        visited = [False] * len(prefix)
        for (i, j) in enumerate(prefix):
            while j < len(prefix) and not visited[j]:
                visited[j] = True
                if j == i:
                    c += 1
                    break
                j = prefix[j]
        return c
    
    def extcount(n, dset, prefix):
        c = cyclecount(prefix)
        return sum(stirling1(n - len(prefix), n - d - c) for d in dset)
    
    def unrank(n, dset, rnk):
        assert rnk >= 0
        choices = set(range(n))
        prefix = []
        while choices:
            for i in sorted(choices):
                prefix.append(i)
                count = extcount(n, dset, prefix)
                if rnk < count:
                    choices.remove(i)
                    break
                del prefix[-1]
                rnk -= count
            else:
                assert False
        return tuple(prefix)
    
    def rank(n, dset, perm):
        assert n == len(perm)
        rnk = 0
        prefix = []
        choices = set(range(n))
        for j in perm:
            choices.remove(j)
            for i in sorted(choices):
                if i < j:
                    prefix.append(i)
                    rnk += extcount(n, dset, prefix)
                    del prefix[-1]
            prefix.append(j)
        return rnk
    
    def degree(perm):
        return len(perm) - cyclecount(perm)
    
    def test(n, dset):
        for (rnk, perm) in enumerate(perm for perm in itertools.permutations(range(n)) if degree(perm) in dset):
            assert unrank(n, dset, rnk) == perm
            assert rank(n, dset, perm) == rnk
    
    test(7, {2, 3, 5})
    
    01234
    31042
    
    permutation cycles (0342)(1)
    degree = (4-1) + (1-1) = 3
    
    def cycles(prefix):
      _cycles = []
      i = j = 0
      visited = set()
    
      while j < len(prefix):
        if prefix[i] == i:
          _cycles.append({"is":[i],"incomplete": False})
          j = j + 1
          i = i + 1
        elif not i in visited:
          cycle = {"is":[],"incomplete": False}
          cycleStart = -1
          while True:
            if i >= len(prefix):
              for k in range(len(_cycles) - 1,-1,-1):
                if any(i in cycle["is"] for i in _cycles[k]["is"]):
                  cycle["is"] = list(set(cycle["is"] + _cycles[k]["is"]))
                  del _cycles[k]
              cycle["incomplete"] = True
              _cycles.append(cycle)
              break
            elif cycleStart == i:
              _cycles.append(cycle)
              break
            else:
              if prefix[i] == j + 1:
                j = j + 1
              visited.add(i)
              if cycleStart == -1:
                cycleStart = i
              cycle["is"].append(i)
              i = prefix[i]
        while j in visited:
          j = j + 1
        i = j
      return _cycles
    
    def degree(cycles):
      d = 0
      for i in cycles:
        if i["incomplete"]:
          d = d + len(i["is"])
        else:
          d = d + len(i["is"]) - 1
      return d
    
    number of permutations of n=5,d=3 that start with "0" = S(4,4-3) = 6
    number of permutations of n=5,d=3 that start with "1" = S(4,4-2) = 11
    
    [just in case you're wondering, I believe the ones starting with "1" are:
     (01)(234)
     (01)(243)
     (201)(34)
     (301)(24)
     (401)(23)
     (2301)(4)
     (2401)(3)
     (3401)(2)
     (3201)(4)
     (4201)(3)
     (4301)(2) notice what's common to all of them?]
    
    number of permutations of n=5,d=3 that start with "2" = S(4,4-2) = 11
    
    01234
    31024 ?
    permutaiton cycles (032)(4)(1)
    degree = (3-1) + (1-1) + (1-1) = 2
    since its degree is different, we will not apply 31024 to our calculation
    
    (031)(24)
    (0321)(4)
    (0341)(2)
    count = 3
    
    def next(prefix,target):
      i = len(prefix) - 1
      if prefix[i] < target[i]:
        prefix[i] = prefix[i] + 1
      elif prefix[i] == target[i]:
        prefix.append(0)
        i = i + 1
      while prefix[i] in prefix[0:i]:
        prefix[i] = prefix[i] + 1
      return prefix
    
    def index(perm,prefix,ix):
      if prefix == perm:
        print ix
      else:
        permD = degree(cycles(perm))
        prefixD = degree(cycles(prefix))
        n = len(perm) - len(prefix)
        k = n - (permD - prefixD)
        if prefix != perm[0:len(prefix)] and permD >= prefixD:
          ix = ix + S[n][k]
        index(perm,next(prefix,perm),ix)
    
    S = [[1]
        ,[0,1]
        ,[0,1,1]
        ,[0,2,3,1]
        ,[0,6,11,6,1]
        ,[0,24,50,35,10,1]]
    
    C:\pypy>pypy test.py REM print(index([3,1,0,4,2],[0],0))
    31
    
    C:\pypy>pypy davids_rank.py REM print(rank(5,{3},[3,1,0,2,4]))
    31
    
    using System;
    using System.Collections.Generic;
    
    namespace WpfPermutations
    {
        public class PermutationOuelletLexico3<T>
        {
            // ************************************************************************
            private T[] _sortedValues;
    
            private bool[] _valueUsed;
    
            public readonly long MaxIndex; // long to support 20! or less 
    
            // ************************************************************************
            public PermutationOuelletLexico3(T[] sortedValues)
            {
                if (sortedValues.Length <= 0)
                {
                    throw new ArgumentException("sortedValues.Lenght should be greater than 0");
                }
    
                _sortedValues = sortedValues;
                Result = new T[_sortedValues.Length];
                _valueUsed = new bool[_sortedValues.Length];
    
                MaxIndex = Factorial.GetFactorial(_sortedValues.Length);
            }
    
            // ************************************************************************
            public T[] Result { get; private set; }
    
            // ************************************************************************
            /// <summary>
            /// Return the permutation relative to the index received, according to 
            /// _sortedValues.
            /// Sort Index is 0 based and should be less than MaxIndex. Otherwise you get an exception.
            /// </summary>
            /// <param name="sortIndex"></param>
            /// <param name="result">Value is not used as inpu, only as output. Re-use buffer in order to save memory</param>
            /// <returns></returns>
            public void GetValuesForIndex(long sortIndex)
            {
                int size = _sortedValues.Length;
    
                if (sortIndex < 0)
                {
                    throw new ArgumentException("sortIndex should be greater or equal to 0.");
                }
    
                if (sortIndex >= MaxIndex)
                {
                    throw new ArgumentException("sortIndex should be less than factorial(the lenght of items)");
                }
    
                for (int n = 0; n < _valueUsed.Length; n++)
                {
                    _valueUsed[n] = false;
                }
    
                long factorielLower = MaxIndex;
    
                for (int index = 0; index < size; index++)
                {
                    long factorielBigger = factorielLower;
                    factorielLower = Factorial.GetFactorial(size - index - 1);  //  factorielBigger / inverseIndex;
    
                    int resultItemIndex = (int)(sortIndex % factorielBigger / factorielLower);
    
                    int correctedResultItemIndex = 0;
                    for(;;)
                    {
                        if (! _valueUsed[correctedResultItemIndex])
                        {
                            resultItemIndex--;
                            if (resultItemIndex < 0)
                            {
                                break;
                            }
                        }
                        correctedResultItemIndex++;
                    }
    
                    Result[index] = _sortedValues[correctedResultItemIndex];
                    _valueUsed[correctedResultItemIndex] = true;
                }
            }
    
            // ************************************************************************
            /// <summary>
            /// Calc the index, relative to _sortedValues, of the permutation received
            /// as argument. Returned index is 0 based.
            /// </summary>
            /// <param name="values"></param>
            /// <returns></returns>
            public long GetIndexOfValues(T[] values)
            {
                int size = _sortedValues.Length;
                long valuesIndex = 0;
    
                List<T> valuesLeft = new List<T>(_sortedValues);
    
                for (int index = 0; index < size; index++)
                {
                    long indexFactorial = Factorial.GetFactorial(size - 1 - index);
    
                    T value = values[index];
                    int indexCorrected = valuesLeft.IndexOf(value);
                    valuesIndex = valuesIndex + (indexCorrected * indexFactorial);
                    valuesLeft.Remove(value);
                }
                return valuesIndex;
            }
    
            // ************************************************************************
        }
    }