Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/12.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
R 求取n个可能值的长度为k的向量的所有非等价置换_R_Algorithm_Function_Permutation_Combinatorics - Fatal编程技术网

R 求取n个可能值的长度为k的向量的所有非等价置换

R 求取n个可能值的长度为k的向量的所有非等价置换,r,algorithm,function,permutation,combinatorics,R,Algorithm,Function,Permutation,Combinatorics,我有一个函数,它接受长度为k的输入向量,其中向量中的每个元素最多可以接受n个值 通常k在6:10范围内,n在2:(k-1)范围内 对于任何给定的(n,k),将有n^k-1个可能向量的置换 目前,我正在将每个整数0:(n^k-1)映射到一个唯一的置换,并在该置换处计算函数,以找到所有可能向量上的最佳输入向量 例如,当n=3和k=6时,映射为: 0:1,1,1,1,1,1 1:1,1,1,1,1,2 2:1,1,1,1,1,3 3:1,1,1,1,2,1 ... 728:3,3,3,3,3,3

我有一个函数,它接受长度为k的输入向量,其中向量中的每个元素最多可以接受n个值

通常k在6:10范围内,n在2:(k-1)范围内

对于任何给定的(n,k),将有n^k-1个可能向量的置换

目前,我正在将每个整数0:(n^k-1)映射到一个唯一的置换,并在该置换处计算函数,以找到所有可能向量上的最佳输入向量

例如,当n=3和k=6时,映射为:

0:1,1,1,1,1,1
1:1,1,1,1,1,2
2:1,1,1,1,1,3 
3:1,1,1,1,2,1
...
728:3,3,3,3,3,3
然而,出于我的目的,一些排列是等价的。您可以将向量视为n个类中k个元素的分配

如果以下两种排列都成立,则两种排列A和B是等效的:

  • A中共享一个类的所有元素,也共享B中的一个类
  • A中所有不共享类的元素,也不共享B中的类
  • 例如: 当n=2和k=6时,向量

    1,2,1,1,2,1 
    2,1,2,2,1,2 
    
    1,2,3,1,2,3
    1,3,2,1,3,2
    2,3,1,2,3,1
    2,1,3,2,1,3
    3,2,1,3,2,1
    3,1,2,3,1,2 
    
    它们是等价的。在这两个向量中,元素{1,3,4,6}共享一个类,元素{2,5}共享一个类

    当n=3和k=6时,向量

    1,2,1,1,2,1 
    2,1,2,2,1,2 
    
    1,2,3,1,2,3
    1,3,2,1,3,2
    2,3,1,2,3,1
    2,1,3,2,1,3
    3,2,1,3,2,1
    3,1,2,3,1,2 
    
    它们都是等价的

    我的目标是找到一种比尝试1:(n^k-1)范围内的每个输入更有效的方法来找到最优向量

    我可以看到两种可能的前进方式:

    备选案文1。列举每一种可能性,然后过滤掉所有等价向量

    选项2:减少我需要提前检查的范围。例如,对于n=3,k=6,我相当有信心(但尚未证明)我不需要检查高于161:1,2,3,3,3的任何内容,并且在1:161范围内也应该有一些等价排列

    我更喜欢选择2

    理想的解决方案是(n,k)的函数,它输出一个向量列表,表示我需要检查的1:n^k-1中的间隔。(n,k)的一个函数输出1:n^k-1中的最大整数/向量,我需要检查它

    作为起点,以下是一些示例R代码:

    vectorFromID <- function(id, n, k) {
      if(id >= n^k) {
        stop('ID too large!')
      }
      remainder <- id
      elements <- list()
      for(i in (k-1):0) {
        elements[[k-i]] <- (remainder  %/% (n ^ i))+1
        remainder <- remainder %% (n ^ i)
      }
      return(unlist(elements))
    }
    
    vectorToID <- function(inputVector, n, k) {
      total <- 0
      for(i in 0:(k-1)) {
        total <- total + (inputVector[i+1]-1) * (n ^ ((k-1)-i))
      }
      return(total)
    }
    
    # generate all possible vectors for n=3, k=6
    all_vectors <- Map(function(x) vectorFromID(x, 3, 6), 0:728)
    

    我还没有完全测试过,但我认为它能满足你的需求。我有三个主要步骤:

  • 应用
    expand.grid
    提供n和k的所有可能排列
  • 将值转换为因子,级别基于外观顺序。然后,将它们转换回数值(在循环中)。e、 g.
    c(1,2,3,1,2,3)
    c(3,2,1,3,2,1)
    将返回为
    c(1,2,3,1,2,3)
    c(1,2,3,1,2,3)
    (即等效值),因为因子水平的顺序相似
  • 只返回唯一的组合。使用
    n=3
    k=6
    ,唯一组合的数量从729减少到162:
  • 功能
    combnmix

    combnmix让我们首先为每个等价类选择一个代表。假设向量p={x_1…x_k}是所有p_i的字典最小值,使得p_i~p

    注意,对于所有j 同样,如果对于每个i,x_i在范围(1..x_j+1)内,那么p是一个代表。 否则存在一些q={y_1…y_n},这样对于一些k,y_i=x_i,对于所有i 因此,对于所有j
    void printResult(std::vector<int>& v){
        for (auto val : v){
            std::cout << val << ' ';
        }
        std::cout << '\n';
    }
    
    void enumerate(std::vector<int>& v, int n, int k, int max){
        if (k == 0){
            printResult(v);
        } else {
            for (int i = 1; i <= std::min(n, max + 1); i++){
                v.push_back(i);
                enumerate(v, n, k - 1, std::max(i, max));
                v.pop_back();
            }
        }
    }
    
    void solve(int n, int k){
        std::vector<int> v;
        enumerate(v, n, k, 0);
    }
    
    void打印结果(std::vector&v){
    用于(自动值:v){
    
    我不确定你是如何进行比较的,但我发现这两种方法给出的结果并不相同。我提出的方法比另一种方法的结果更独特(例如,n=5,k=7有4875个唯一性,而不是855;n=3,k=6有162个唯一性,而不是122个)。您编写的解决方案生成了一个包含122行的数据帧,但标签增加到162行。请尝试比较rownames(res)和nrow(res)。您说得对-我很抱歉。@denis的算法非常有趣-我以前没有见过在循环中使用自身的函数。
    void printResult(std::vector<int>& v){
        for (auto val : v){
            std::cout << val << ' ';
        }
        std::cout << '\n';
    }
    
    void enumerate(std::vector<int>& v, int n, int k, int max){
        if (k == 0){
            printResult(v);
        } else {
            for (int i = 1; i <= std::min(n, max + 1); i++){
                v.push_back(i);
                enumerate(v, n, k - 1, std::max(i, max));
                v.pop_back();
            }
        }
    }
    
    void solve(int n, int k){
        std::vector<int> v;
        enumerate(v, n, k, 0);
    }