zoukankan      html  css  js  c++  java
  • 康托展开和逆康托展开

    问题:给定的全排列,计算出它是第几个排列?

      对于全排列,不清楚的可以参考全排列

      方法:康托展开

      对于一个长度为 n 的排列 num[1..n], 其序列号 X 为

      X = a[1]*(n-1)! + a[2]*(n-2)! +...+ a[i]*(n-i)! +...+ a[n-1]*1! + a[n]*0!

      其中a[i]表示在num[i+1..n]中比num[i]小的数的数量

      写做伪代码为:

    Cantor(num[])
        X = 0
        For i = 1 .. n
            tp = 0
            For j = i + 1 .. n
                If (num[j] < num[i]) Then
                    tp = tp + 1
                End If
            End For
            X = X + tp * (n - i)!
        End For
        Return X

      实现代码为:

    // 给定一个全排列, 计算它是第几个排列
    
    #include <iostream>
    #include <algorithm>
    #include <string>
    using namespace std;
    
    // string 转 int 
    void strToNum(string s, int num[10]){
        int len = s.length();
        num[0] = len;
        for(int i = 1; i<= len; i++){
            num[i] = s[i-1] - '0';
        }
    }
    
    // 输出 
    void Pri(int num[10]){
        for(int i = 1; i<= num[0]; i++){
            cout << num[i];
        }
        cout << endl;
    }
    
    // 阶乘 
    int factorial(int n){
        int x = 1;
        for(int i = n; i>=2; i--){
            x = x*i;
        }
        return x;
    }
    
    // 康托展开 
    int Cantor(int num[10]){
        int X = 0;
        for(int i = 1; i<= num[0]; i++){
            int tp = 0;
            for(int j = i+1; j<= num[0]; j++){
                if(num[j]< num[i]){
                    tp++;
                }
            }
            X += tp*factorial(num[0]-i); 
        }
        return X;
    }
    
    int main(){
        int num[10];
        string str;
        cin >> str;
        strToNum(str, num);
        Pri(num);
        int X = Cantor(num);
        cout << X << endl;
    }
    Cantor

    问题:已知X,如何去反向求解出全排列?

      方法: 逆康托展开
      根据 康托展开的公式,可以推出

      因为    a[i] <=  n-i
           X = a[1]*(n-1)! + a[2]*(n-2)! +...+ a[i]*(n-i)! +...+ a[n-1]*1! + a[n]*0!   所以 a[i]
    *(n-i)! <= (n-i)(n-i)! <= (n-i+1)!

      那么也就是说,如果用 X 除以 (n-1)! 得到商 c 和余数 r,其中 c 就等于 a[1], r 等于后面的部分

      写做伪代码为:

    unCantor(X):
        a = []
        num = []
        used = [] // 长度为n的boolean数组,初始为false
        For i = 1 .. n
            a[i] = X / (n - i)!
            X = X mod (n - i)!
            cnt = 0
            For j = 1 .. n
                If (used[j]) Then
                    cnt = cnt + 1
                    If (cnt == a[i] + 1) Then
                        num[i] = j
                        used[j] = true
                        Break
                    End If
                End If
            End For
        End For
        Return num

      代码实现为:

    // 给定排列元素 num 数组以及排列序号 X,求该排列
    // 排列从 0 开始 
    #include <iostream>
    #include <algorithm>
    #include <string>
    #define Inf 100000
    using namespace std;
    
    // string 转 int 
    void strToNum(string s, int num[10]){
        int len = s.length();
        num[0] = len;
        for(int i = 1; i<= len; i++){
            num[i] = s[i-1] - '0';
        }
    }
    
    // 输出 
    void Pri(int num[10]){
        for(int i = 1; i<= num[0]; i++){
            cout << num[i];
        }
        cout << endl;
    }
    
    // 阶乘 
    int factorial(int n){
        int x = 1;
        for(int i = n; i>=2; i--){
            x = x*i;
        }
        return x;
    }
    
    // 逆康托展开
    void inverseCantor(int num[10], int n, int out[10]){
        out[0] = num[0];
        for(int i = 1; i<= out[0]; i++){
            int t = factorial(out[0]-i);
            out[i] = num[n/t+1];
            num[n/t+1] = Inf;
            sort(num+1, num+num[0]+1);
            num[0]--;
            n = n%t;
        } 
    }
    
    int main(){
        int X, num[10], out[10];
        string str;
        cin >> str;
        cin >> X;
        strToNum(str, num);
        sort(num+1, num+num[0]+1);
        Pri(num);
        // num 数组已排好序 
        inverseCantor(num, X, out); 
        Pri(out);
        return 0;
    } 
    unCantor

     

    转载请注明出处:http://www.cnblogs.com/ygdblogs
  • 相关阅读:
    iOS:Core Data 中的简单ORM
    Win8:Snap 实现
    js: 删除node的所有child
    WinJS:Listview item 设置背景透明
    iOS: 消息通信中的Notification&KVO
    win8: 清除iframe的缓存
    What's New in iOS7,iOS7新特性介绍
    "Entity Framework数据插入性能追踪"读后总结
    夜,思考——我想要的到底是什么?
    【查询】—Entity Framework实例详解
  • 原文地址:https://www.cnblogs.com/ygdblogs/p/5551367.html
Copyright © 2011-2022 走看看