<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

        在上一篇的方法一里,我們使用把數組的下標每次增加1的方法得到重復的全排列,然后再挑出不重復的全排列。如下圖所示,綠顏色表示想要得到的結果。
      0 0 0
      0 0 1
      0 0 2
      0 1 0
      0 1 1
      0 1 2
      0 2 0
      0 2 1
      0 2 2
      1 0 0
      1 0 1
      1 0 2
      1 1 0
      1 1 1
      1 1 2
      1 2 0
      1 2 1
      1 2 2
      2 0 0
      2 0 1
      2 0 2
      2 1 0
      2 1 1
      2 1 2
      2 2 0
      2 2 1
      2 2 2
        這種方法雖然簡單,但是效率比較差。要生成n個元素的全排列需要遍歷 nn 次才能得到 n! 個解(看上面那個綠色和黑色的下標的比例也可以有一個直觀的感覺)。能不能直接把當前排列增加 i 得到下一個排列呢?例如,把 012 增加 2 得到 021 (按 3 進制計算),把 021 增加 4 得到 102……把 201 增加 2 得到 210?可以看到,有時候是增加 2,有時候是增加 4,很難摸清其中的規律(如果想求 [1,2,3,4] 的全排列,會發現有時候需要增加 3,有時候需要增加 6,有時候需要增加 9,甚至有時候需要增加 21)。這里的難點是,把數字增加 i 之后,可能會發生一連串的進位,而你很難知道這一連串的進位之后,哪兩個位上的數字會重復。當問題的變量很多,而這些變量又相互影響時,問題就會變得復雜而難以解決。要想簡化問題,就必須找到一個一致的方法表達這些相互影響的變量對結果的影響。把多個維度疊加到一個維度之上,是簡化問題的常用手段。譬如,能否找到一個一致的方法把全排列映射為一個每次增加1的序列呢? 也就是:
      [0,1,2] => 0
      [0,2,1] => 1
      [1,0,2] => 2
      [1,2,0] => 3
      [2,0,1] => 4
      [2,1,0] => 5
      這樣給出[2,0,1]就可以知道它是第5個排列了;反過來,根據這種獨特的映射方法,也有可能知道第5個排列是[2,0,1]。這個映射可以使用康托展開來實現。

      康托展開

        康托展開的公式是 X=an*(n-1)!+an-1*(n-2)!+...+ai*(i-1)!+...+a2*1!+a1*0! 其中,ai為當前未出現的元素中是排在第幾個(從0開始)。
        這個公式可能看著讓人頭大,最好舉個例子來說明一下。例如,有一個數組 s = ["A", "B", "C", "D"],它的一個排列 s1 = ["D", "B", "A", "C"],現在要把 s1 映射成 X。n 指的是數組的長度,也就是4,所以
      X(s1) = a4*3! + a3*2! + a2*1! + a1*0!
      關鍵問題是 a4、a3、a2 和 a1 等于啥?
      a4 = "D" 這個元素在子數組 ["D", "B", "A", "C"] 中是第幾大的元素。"A"是第0大的元素,"B"是第1大的元素,"C" 是第2大的元素,"D"是第3大的元素,所以 a4 = 3。
      a3 = "B" 這個元素在子數組 ["B", "A", "C"] 中是第幾大的元素。"A"是第0大的元素,"B"是第1大的元素,"C" 是第2大的元素,所以 a3 = 1。
      a2 = "A" 這個元素在子數組 ["A", "C"] 中是第幾大的元素。"A"是第0大的元素,"C"是第1大的元素,所以 a2 = 0。
      a1 = "C" 這個元素在子數組 ["C"] 中是第幾大的元素。"C" 是第0大的元素,所以 a1 = 0。(因為子數組只有1個元素,所以a1總是為0)
      所以,X(s1) = 3*3! + 1*2! + 0*1! + 0*0! = 20
      康托展開的C#代碼如下:
      // 返回s的康托展開值
      static long X(string[] s)
      {
          long result = 0;
          int len = s.Length;
          for (int i = 0; i < len; i++)
          {
              result += An(s, i) * Factorial(len - i - 1);
          }
          return result;
      }
      
      // 返回 s[n] 是 s[n..length] 中第幾大的元素
      static int An(string[] s, int n)
      {
          int result = 0;
          for (int i = n + 1; i < s.Length; i++)
          {
              if (s[n].CompareTo(s[i]) >= 0)
                  result++;
          }
          return result;
      }
      
      // 返回 input 的階乘
      static int Factorial(int input)
      {
          int result = 1;
          for (int i = 2; i <= input; i++)
          {
              result = result * i;
          }
          return result;
      }
      

      測試一下:
      string[] s = new string[] { "A", "B", "C" };
      foreach (string[] p in Permutation2(s))
      {
          Console.WriteLine(p.Montage(t => t, " ") + " | " + X(p).ToString());
      }
      


      Permutation2() 和 Montage() 函數請參考上一篇。測試輸出如下:
      A B C | 0
      A C B | 1
      B A C | 2
      B C A | 3
      C A B | 4
      C B A | 5

      通過康托逆展開生成全排列

        如果已知 s = ["A", "B", "C", "D"],X(s1) = 20,能否推出 s1 = ["D", "B", "A", "C"] 呢?
        因為已知 X(s1) = a4*3! + a3*2! + a2*1! + a1*0! = 20,所以問題變成由 20 能否唯一地映射出一組 a4、a3、a2、a1?如果不考慮 ai 的取值范圍,有
      3*3! + 1*2! + 0*1! + 0*0! = 20
      2*3! + 4*2! + 0*1! + 0*0! = 20
      1*3! + 7*2! + 0*1! + 0*0! = 20
      0*3! + 10*2! + 0*1! + 0*0! = 20
      0*3! + 0*2! + 20*1! + 0*0! = 20
      等等。但是滿足 0 <= ai <= n-1 的只有第一組。可以使用輾轉相除的方法得到 ai,如下圖所示:

      知道了a4、a3、a2、a1的值,就可以知道s1[0] 是子數組["A", "B", "C", "D"]中第3大的元素 "D",s1[1] 是子數組 ["A", "B", "C"] 中第1大的元素"B",s1[2] 是子數組 ["A", "C"] 中第0大的元素"A",s[3] 是子數組 ["C"] 中第0大的元素"C",所以s1 = ["D", "B", "A", "C"]。
      這樣我們就能寫出一個函數 Permutation3(),它可以返回  s 的第 m 個排列。

      // 返回 s 的第 m 個排列(m 從 0 開始)。要求 s 是升序排列的
      static string[] Permutation3(string[] s, int m)
      {
          IList<string> sub = new List<string>(s);
          IList<string> result = new List<string>();
          for (int i = s.Length - 1; i >= 0; i--)
          {
              int f = Factorial(i);
              int ai = m / f;
              string item = sub[ai]; // 由于數組是升序排列的,所以第 ai 大的元素就是 sub[ai]
              result.Add(item);
              sub.RemoveAt(ai);
              m = m % f;
          }
          return result.ToArray();
      }
      

      測試一下:

      string[] s = new string[] { "A", "B", "C", "D" };
      for (int i = 0; i < Factorial(s.Length); i++)
      {
          string[] s1 = Permutation3(s, i);
          Console.WriteLine(s1.Montage(t => t, " "));
      }
      


      附錄 康托展開是怎么來的?

        很顯然,康托展開是本文的關鍵所在。你說康托他老人家當初是怎么想出來這種展開的方法的呢?我們還是以 s=["A", "B", "C"] 為例:

      A B C | 0
      A C B | 1
      B A C | 2
      B C A | 3
      C A B | 4
      C B A | 5

        他的思路可能是這樣的:首先,確定一個目標:將每個排列映射為一個自然數,這個自然數是順序增長的(或者至少要有一定的規律)。要說映射成自然數,第一個想到的方法自然是把數組的下標當作一個n進制的數字,但是正如本文開篇所討論的,這個數字并沒有什么規律;第二個方法是計數,也就是令 X = 當前排列之前有多少個排列。例如 A B C 是第一個排列,它前面沒有任何排列,所以 X(ABC) = 0;A C B 前面有一個排列,所以 X(ACB) = 1……那么如何才能知道 X(BCA) = 3 也就是 B C A 的前面有3個排列呢?這里的技巧仍然是分解——把問題分隔成相互獨立有限的小塊。具體的方法是:先求出 B 第一次出現在最高位(也就是 B A C 這個排列)時前面有幾個排列,再求出 B C A 是 B A C 后面第幾個排列,把這個兩個數相加就是想要的結果了。
        先看第一個問題:B 第一次出現在最高位(也就是 B A C 這個排列)時前面有幾個排列?由于已知 B A C 前面的排列一定是 A 開頭的,所以只有 A 后面的兩個元素可以變化,所以排列數是 P(2,2) = 2! 個。
        第二個問題:B C A 是 B A C 后面第幾個排列?因為都是 B 開頭的,所以可以把開頭的 B 忽略,問題變成 C A 是 A C 后面的第幾個排列?同樣,可以先考慮 C 第一次出現在最高位時前面有幾個排列,因為 C A 前面的排列肯定是 A 開頭的,所以只有 A 后面的一個元素可以變化,所以排列數是 P(1,1) = 1! 個。
        所以 X(BCA) = 2! + 1! = 3
        再例如想求 X(CBA),同樣是先考慮 C 第一次出現在最高位時前面有多少個排列,因為比 C 小的元素有 A 和 B 兩個,所以是 2*2! 個。再求出 B  A 是 A B 后面的第 1! 個排列。就可以知道 X(CBA) = 2*2! + 1! = 5 了。

      感謝徐少俠的幫助!

      posted on 2011-04-25 23:32  1-2-3  閱讀(5494)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 久久婷婷五月综合色精品| 亚洲高清免费在线观看| 在线视频一区二区三区色| 综合亚洲网| 激情五月日韩中文字幕| 国产三级视频网站| 日韩深夜免费在线观看| 国产不卡一区在线视频| 色欲AV无码一区二区人妻| 国产偷国产偷亚洲综合av| 国产婷婷精品av在线| 久久www免费人成看片中文| 亚洲中文字幕一二区日韩| 成年女人免费毛片视频永久| 国产成AV人片久青草影院| 国产亚洲一区二区三不卡| 毛片久久网站小视频| 亚洲av激情久久精品人| 4480yy亚洲午夜私人影院剧情| 国产亚洲无线码一区二区| 亚洲中文字幕无码久久精品1| 亚洲激情视频一区二区三区| 欧美丰满熟妇bbbbbb| 亚洲成人av在线资源| 亚洲丰满熟女一区二区蜜桃| 噜噜久久噜噜久久鬼88| 无码人妻精品一区二区三区蜜桃 | 日韩有码精品中文字幕| 国产一区二区三区AV在线无码观看| 天堂mv在线mv免费mv香蕉| 狠狠色噜噜狠狠狠狠蜜桃| 国产精品久久毛片av大全日韩| 色综合视频一区二区三区| 日韩高清国产中文字幕| 青草成人精品视频在线看| 国产一卡2卡三卡4卡免费网站| 国产中年熟女大集合| 国产日韩AV免费无码一区二区三区 | 成人午夜免费无码视频在线观看| 中文人妻AV高清一区二区| 国产呻吟久久久久久久92|