アットウィキロゴ

csharp_combination


   public class Combination
   {
       private long n = 0;
       private long k = 0;
       private long[] data = null;

       public Combination(long n, long k)
       {
           if (n < 0 || k < 0) // 通常は n >= k
               throw new Exception("コンストラクタのパラメータが負の数です");

           this.n = n;
           this.k = k;
           this.data = new long[k];
           for (long i = 0; i < k; ++i)
               this.data[i] = i;
       } // Combination(n,k)

       public Combination(long n, long k, long[] a) // a[] の組み合わせ
       {
           if (k != a.Length)
               throw new Exception("配列の長さが k に等しくありません");

           this.n = n;
           this.k = k;
           this.data = new long[k];
           for (long i = 0; i < a.Length; ++i)
               this.data[i] = a[i];

           if (!this.IsValid())
               throw new Exception("配列の値が正しくありません");
       } // (n,k,a) の組み合わせ

       public bool IsValid()
       {
           if (this.data.Length != this.k)
               return false; // 破損

           for (long i = 0; i < this.k; ++i)
           {
               if (this.data[i] < 0 || this.data[i] > this.n - 1)
                   return false; // 範囲外の値

               for (long j = i + 1; j < this.k; ++j)
                   if (this.data[i] >= this.data[j])
                       return false; // 重複しているか、辞書式でない
           }

           return true;
       } // IsValid()

       public override string ToString()
       {
           string s = "{ ";
           for (long i = 0; i < this.k; ++i)
               s += this.data[i].ToString() + " ";
           s += "}";
           return s;
       } // ToString()

       public Combination Successor()
       {
           if (this.data[0] == this.n - this.k)
               return null;

           Combination ans = new Combination(this.n, this.k);

           long i;
           for (i = 0; i < this.k; ++i)
               ans.data[i] = this.data[i];

           for (i = this.k - 1; i > 0 && ans.data[i] == this.n - this.k + i; --i)
               ;

           ++ans.data[i];

           for (long j = i; j < this.k - 1; ++j)
               ans.data[j + 1] = ans.data[j] + 1;

           return ans;
       } // Successor()

       public static long Choose(long n, long k)
       {
           if (n < 0 || k < 0)
               throw new Exception("Choose() の負のパラメータは無効です");
           if (n < k)
               return 0;  // 特殊なケース
           if (n == k)
               return 1;

           long delta, iMax;

           if (k < n - k) // 例: Choose(100,3)
           {
               delta = n - k;
               iMax = k;
           }
           else         // 例: Choose(100,97)
           {
               delta = k;
               iMax = n - k;
           }

           long ans = delta + 1;

           for (long i = 2; i <= iMax; ++i)
           {
               checked { ans = (ans * (delta + i)) / i; }
           }

           return ans;
       } // Choose()

       // 組み合わせ C(n,k) の辞書式順序で m 番目の要素を返します
       public Combination Element(long m)
       {
           long[] ans = new long[this.k];

           long a = this.n;
           long b = this.k;
           long x = (Choose(this.n, this.k) - 1) - m; // x は m の "デュアル"

           for (long i = 0; i < this.k; ++i)
           {
               ans[i] = LargestV(a, b, x); // 最大値は v です。ここで、v < a および vCb < x
               x = x - Choose(ans[i], b);
               a = ans[i];
               b = b - 1;
           }

           for (long i = 0; i < this.k; ++i)
           {
               ans[i] = (n - 1) - ans[i];
           }

           return new Combination(this.n, this.k, ans);
       } // Element()

       // 最大値 v を返します。ここで、v < a および Choose(v,b) <= x
       private static long LargestV(long a, long b, long x)
       {
           long v = a - 1;

           while (Choose(v, b) > x)
               --v;

           return v;
       } // LargestV()

   } // Combination クラス

   class Program
   {
       static void Main(string[] args)
       {
           Combination c = new Combination(5, 2);
           Console.WriteLine("\nWith n=5 and k=3 there are " + Combination.Choose(5, 3) + " combination elements.");

           // 全組み合わせを表示する
           Console.WriteLine("\nThe elements are:");
           for (int i = 0; i < 10; ++i)
           {
               Console.WriteLine(i + ": " + c.ToString());
               c = c.Successor();
           }

           // コンソールが入力されたインデックスの要素を表示
           c = new Combination(5, 2);
           Console.Write("\nEnter an index: ");
           int m = int.Parse(Console.ReadLine());
           Console.WriteLine("That combination element is: " + c.Element(m).ToString());
       }
   }

[出力結果]
   With n=5 and k=3 there are 10 combination elements.

   The elements are:
   0: { 0 1 }
   1: { 0 2 }
   2: { 0 3 }
   3: { 0 4 }
   4: { 1 2 }
   5: { 1 3 }
   6: { 1 4 }
   7: { 2 3 }
   8: { 2 4 }
   9: { 3 4 }

   Enter an index: 3
   That combination element is: { 0 4 }
最終更新:2009年02月13日 15:18