競技プログラミング用のライブラリ
前のライブラリへ
005-03 集合を指定した分割数に分割
集合を指定した分割数に分割するメソッドを実装します。
C#のソース
using System;
using System.Collections.Generic;
using System.Linq;
class Program
{
static void Main()
{
// セパレータとInt型の列挙を引数として、結合したstringを返す
Func<string, IEnumerable<int>, string> IntEnumJoin = (pSeparater, pEnum) =>
{
string[] StrArr = Array.ConvertAll(pEnum.ToArray(), pX => pX.ToString());
return string.Join(pSeparater, StrArr);
};
var ValList = new List<int>();
for (int I = 1; I <= 3; I++) {
ValList.Add(I * 10);
}
List<List<int[]>> BunkatuArrListList =
BunkatuArrListListClass<int>.DeriveBunkatuArrListList(ValList, 2);
foreach (List<int[]> EachBunkatuArrList in BunkatuArrListList) {
Console.WriteLine("■■■分割結果■■■");
foreach (int[] EachBunkatuArr in EachBunkatuArrList) {
Console.WriteLine(IntEnumJoin(" ", EachBunkatuArr));
}
}
}
}
#region BunkatuArrListListClass
// 集合を指定した分割数に分割
internal static class BunkatuArrListListClass<Type>
{
// 列挙と分割数を引数として、配列のListのListを返す
internal static List<List<Type[]>> DeriveBunkatuArrListList(IEnumerable<Type> pBaseEnum, int pDivCnt)
{
Type[] BaseArr = pBaseEnum.ToArray();
var WillReturn = new List<List<Type[]>>();
var DESResultList = new List<JyoutaiDef>();
var Stk = new Stack<JyoutaiDef>();
JyoutaiDef WillPush;
WillPush.BitSetList = new List<int>();
WillPush.BitSetList.Add(0);
WillPush.UseBitSet = 0;
Stk.Push(WillPush);
int AllBitOn = (1 << BaseArr.Length) - 1;
int UB = BaseArr.GetUpperBound(0);
while (Stk.Count > 0) {
JyoutaiDef Popped = Stk.Pop();
if (Popped.UseBitSet == AllBitOn) {
if (Popped.BitSetList.Count == pDivCnt) {
DESResultList.Add(Popped);
}
continue;
}
if (Popped.BitSetList.Last() == 0) {
// 最小添字が未使用なら、必ず使用する
for (int I = 0; I <= UB; I++) {
int CurrBit = 1 << I;
if ((Popped.UseBitSet & CurrBit) > 0) continue;
WillPush.BitSetList = new List<int>(Popped.BitSetList);
int LastInd = WillPush.BitSetList.Count - 1;
WillPush.BitSetList[LastInd] |= CurrBit;
WillPush.UseBitSet = Popped.UseBitSet | CurrBit;
Stk.Push(WillPush);
break;
}
}
else {
// 分割を増やす場合
if (Popped.BitSetList.Count < pDivCnt) {
WillPush.BitSetList = new List<int>(Popped.BitSetList);
WillPush.BitSetList.Add(0);
WillPush.UseBitSet = Popped.UseBitSet;
Stk.Push(WillPush);
}
// 分割せずに追加する場合
int LastVal = Popped.BitSetList.Last();
int CurrInd = -1;
for (int I = UB; 0 <= I; I--) {
int CurrBit = 1 << I;
if ((LastVal & CurrBit) == 0) continue;
CurrInd = I;
break;
}
for (int I = CurrInd + 1; I <= UB; I++) {
int CurrBit = 1 << I;
if ((Popped.UseBitSet & CurrBit) > 0) continue;
WillPush.BitSetList = new List<int>(Popped.BitSetList);
int LastInd = WillPush.BitSetList.Count - 1;
WillPush.BitSetList[LastInd] |= CurrBit;
WillPush.UseBitSet = Popped.UseBitSet | CurrBit;
Stk.Push(WillPush);
}
}
}
foreach (JyoutaiDef EachDESResult in DESResultList) {
var ResultArrList = new List<Type[]>();
foreach (int EachBitSet in EachDESResult.BitSetList) {
var CurrList = new List<Type>();
for (int I = 0; I <= UB; I++) {
int CurrBit = 1 << I;
if ((EachBitSet & CurrBit) == 0) continue;
CurrList.Add(BaseArr[I]);
}
ResultArrList.Add(CurrList.ToArray());
}
WillReturn.Add(ResultArrList);
}
return WillReturn;
}
struct JyoutaiDef
{
internal List<int> BitSetList;
internal int UseBitSet;
}
}
#endregion
実行結果
■■■分割結果■■■
10 30
20
■■■分割結果■■■
10 20
30
■■■分割結果■■■
10
20 30
解説
深さ優先探索を使ってます。