トップページに戻る    次のC#のサンプルへ    前のC#のサンプルへ

Problem181 2色の物体をグループ分けする場合の数

問題

3つの黒い物 B と1つの白い物 W を持っているとき,
これらは7通りにグループ分け出来る.
(BBBW)
(B,BBW)
(B,B,BW)
(B,B,B,W)
(B,BB,W)
(BBB,W)
(BB,BW)

60個の黒い物 B と40個の白い物 W は何通りにグループ分け出来るか?


ソース

using System;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
        Solve(3, 1);
        Solve(60, 40);
    }

    struct PairInfoDef
    {
        internal int BCnt;
        internal int WCnt;
    }

    static void Solve(int pBCnt, int pWCnt)
    {
        //場合の数[Bの個数,Wの個数]なDP表
        long[,] DPArr = new long[pBCnt + 1, pWCnt + 1];
        DPArr[0, 0] = 1;

        IEnumerable<PairInfoDef> PairInfoEnum = DerivePairInfoEnum(pBCnt, pWCnt);

        foreach (PairInfoDef EachPairInfo in PairInfoEnum) {
            for (int I = 0; I <= pBCnt; I++) {
                int NewI = I + EachPairInfo.BCnt;
                if (NewI > pBCnt) break;

                for (int J = 0; J <= pWCnt; J++) {
                    if (DPArr[I, J] == 0) continue;

                    int NewJ = J + EachPairInfo.WCnt;
                    if (NewJ > pWCnt) break;

                    DPArr[NewI, NewJ] += DPArr[I, J];
                }
            }
        }
        Console.WriteLine("Bが{0}個で、Wが{1}個だと、{2}通り", pBCnt, pWCnt, DPArr[pBCnt, pWCnt]);
    }

    //BとWの組み合わせの列挙を返す
    static IEnumerable<PairInfoDef> DerivePairInfoEnum(int pBCnt, int pWCnt)
    {
        for (int I = 0; I <= pBCnt; I++) {
            for (int J = 0; J <= pWCnt; J++) {
                //両方とも0個は不可
                if (I == 0 && J == 0) continue;

                PairInfoDef WillReturn;
                WillReturn.BCnt = I;
                WillReturn.WCnt = J;
                yield return WillReturn;
            }
        }
    }
}


実行結果

Bが3個で、Wが1個だと、7通り
Bが60個で、Wが40個だと、83735848679360680通り


解説

動的計画法で解いてます。