競技プログラミング用のライブラリ
次のライブラリへ
前のライブラリへ
005-01 C++のnext_permutation、prev_permutation
C#で、C++のnext_permutationとprev_permutationを実装します。
C#のソース
using System;
using System.Collections.Generic;
using System.Linq;
class Program
{
static void Main()
{
Console.WriteLine("■■■昇順の列挙■■■");
string[] BaseArr1 = new string[] { "1", "2", "3" };
foreach (string[] EachStrArr in CppPermutationClass<string>.DerivePermutation(BaseArr1)) {
Array.ForEach(EachStrArr, pX => Console.Write(pX));
Console.WriteLine();
}
Console.WriteLine("■■■降順の列挙■■■");
string[] BaseArr2 = new string[] { "3", "2", "1" };
do {
Array.ForEach(BaseArr2, pX => Console.Write(pX));
Console.WriteLine();
} while (CppPermutationClass<string>.PrevPermutation(ref BaseArr2));
}
}
#region CppPermutationClass
internal static class CppPermutationClass<Type> where Type : IComparable
{
// C++のNextPermutationの結果の列挙を返す
internal static IEnumerable<Type[]> DerivePermutation(IEnumerable<Type> pEnum)
{
Type[] wkArr = pEnum.ToArray();
do {
yield return wkArr;
} while (NextPermutation(ref wkArr));
}
// C++のNextPermutationを模倣
internal static bool NextPermutation(ref Type[] pArr)
{
// 右から左に見ていき、初めて小さくなった要素を求める
int WillChangeInd = -1;
for (int I = pArr.GetUpperBound(0) - 1; I >= 0; I--) {
if (pArr[I].CompareTo(pArr[I + 1]) < 0) {
WillChangeInd = I;
break;
}
}
if (WillChangeInd == -1) {
return false;
}
// 初めて小さくなった要素より右の変更すべき要素を求める
int MinValInd = WillChangeInd + 1;
for (int I = WillChangeInd + 2; I <= pArr.GetUpperBound(0); I++) {
if (pArr[WillChangeInd].CompareTo(pArr[I]) >= 0) continue;
if (pArr[MinValInd].CompareTo(pArr[I]) >= 0) {
MinValInd = I;
}
}
// 変更すべき要素と3角交換
Type wkStr = pArr[WillChangeInd];
pArr[WillChangeInd] = pArr[MinValInd];
pArr[MinValInd] = wkStr;
// 正順で連結
var ResultList = new List<Type>();
for (int I = 0; I <= WillChangeInd; I++) {
ResultList.Add(pArr[I]);
}
// 逆順で連結
for (int I = pArr.GetUpperBound(0); I >= WillChangeInd + 1; I--) {
ResultList.Add(pArr[I]);
}
pArr = ResultList.ToArray();
return true;
}
// C++のPrevPermutationを模倣
internal static bool PrevPermutation(ref Type[] pArr)
{
// 右から左に見ていき、初めて大きくなった要素を求める
int WillChangeInd = -1;
for (int I = pArr.GetUpperBound(0) - 1; I >= 0; I--) {
if (pArr[I].CompareTo(pArr[I + 1]) > 0) {
WillChangeInd = I;
break;
}
}
if (WillChangeInd == -1) {
return false;
}
// 初めて大きくなった要素より右の変更すべき要素を求める
int MinValInd = WillChangeInd + 1;
for (int I = WillChangeInd + 2; I <= pArr.GetUpperBound(0); I++) {
if (pArr[WillChangeInd].CompareTo(pArr[I]) <= 0) continue;
if (pArr[MinValInd].CompareTo(pArr[I]) <= 0) {
MinValInd = I;
}
}
// 変更すべき要素と3角交換
Type wkStr = pArr[WillChangeInd];
pArr[WillChangeInd] = pArr[MinValInd];
pArr[MinValInd] = wkStr;
// 正順で連結
var ResultList = new List<Type>();
for (int I = 0; I <= WillChangeInd; I++) {
ResultList.Add(pArr[I]);
}
// 逆順で連結
for (int I = pArr.GetUpperBound(0); I >= WillChangeInd + 1; I--) {
ResultList.Add(pArr[I]);
}
pArr = ResultList.ToArray();
return true;
}
}
#endregion
実行結果
■■■昇順の列挙■■■
123
132
213
231
312
321
■■■降順の列挙■■■
321
312
231
213
132
123
解説