AtCoderのABC
次のABCの問題へ
前のABCの問題へ
ABC187-F Close Group
C#のソース
using System;
using System.Collections.Generic;
using System.Linq;
class Program
{
static string InputPattern = "InputX";
static List<string> GetInputList()
{
var WillReturn = new List<string>();
if (InputPattern == "Input1") {
WillReturn.Add("3 2");
WillReturn.Add("1 2");
WillReturn.Add("1 3");
//2
}
else if (InputPattern == "Input2") {
WillReturn.Add("4 6");
WillReturn.Add("1 2");
WillReturn.Add("1 3");
WillReturn.Add("1 4");
WillReturn.Add("2 3");
WillReturn.Add("2 4");
WillReturn.Add("3 4");
//1
}
else if (InputPattern == "Input3") {
WillReturn.Add("10 11");
WillReturn.Add("9 10");
WillReturn.Add("2 10");
WillReturn.Add("8 9");
WillReturn.Add("3 4");
WillReturn.Add("5 8");
WillReturn.Add("1 8");
WillReturn.Add("5 6");
WillReturn.Add("2 5");
WillReturn.Add("3 6");
WillReturn.Add("6 9");
WillReturn.Add("1 9");
//5
}
else if (InputPattern == "Input4") {
WillReturn.Add("18 0");
//18
}
else {
string wkStr;
while ((wkStr = Console.ReadLine()) != null) WillReturn.Add(wkStr);
}
return WillReturn;
}
static int[] GetSplitArr(string pStr)
{
return (pStr == "" ? new string[0] : pStr.Split(' ')).Select(pX => int.Parse(pX)).ToArray();
}
static void Main()
{
List<string> InputList = GetInputList();
int[] wkArr = { };
Action<string> SplitAct = (pStr) => wkArr = GetSplitArr(pStr);
SplitAct(InputList[0]);
int NodeCnt = wkArr[0];
var EdgeHashSet = new HashSet<int>();
foreach (string EachStr in InputList.Skip(1)) {
SplitAct(EachStr);
int A = wkArr[0];
int B = wkArr[1];
EdgeHashSet.Add(GetEdgeHash(A, B));
}
int AllBitON = (1 << NodeCnt) - 1;
// 完全グラフを作れるノードの組み合わせのSet
var OKBitSet = new HashSet<int>();
for (int I = 1; I <= AllBitON; I++) {
bool IsOK = true;
for (int J = 0; J <= NodeCnt - 1; J++) {
for (int K = J + 1; K <= NodeCnt - 1; K++) {
int Bit1 = 1 << J;
int Bit2 = 1 << K;
if ((Bit1 & I) == 0) continue;
if ((Bit2 & I) == 0) continue;
int Hash = GetEdgeHash(J + 1, K + 1);
if (EdgeHashSet.Contains(Hash) == false) {
IsOK = false;
break;
}
}
if (IsOK == false) break;
}
if (IsOK) {
OKBitSet.Add(I);
}
}
// 最小スコア[使用済のBitSet]なインラインDP表
int[] DPArr = new int[AllBitON + 1];
for (int I = 0; I <= AllBitON; I++) {
if (OKBitSet.Contains(I)) {
DPArr[I] = 1;
}
else {
DPArr[I] = int.MaxValue;
}
}
for (int I = 0; I <= AllBitON; I++) {
foreach (int EachSubSet in DeriveEnumSubSet(I)) {
int Bit1 = EachSubSet;
int Bit2 = I - EachSubSet;
if (DPArr[Bit1] == int.MaxValue) continue;
if (DPArr[Bit2] == int.MaxValue) continue;
DPArr[I] = Math.Min(DPArr[I], DPArr[Bit1] + DPArr[Bit2]);
}
}
Console.WriteLine(DPArr[AllBitON]);
}
// 枝のハッシュ値を求める
static int GetEdgeHash(int pVal1, int pVal2)
{
int Min = Math.Min(pVal1, pVal2);
int Max = Math.Max(pVal1, pVal2);
return Min * 100 + Max;
}
// 引数のBitSetの部分集合の列挙を返す
static IEnumerable<int> DeriveEnumSubSet(int pBase)
{
int pCurr = pBase;
while (true) {
yield return pCurr;
if (pCurr == 0) break;
pCurr = (pCurr - 1) & pBase;
}
}
}
解説
最初に完全グラフになれるビットの組み合わせを列挙します。
次に2つの組み合わせごとに最小コストを求めるDPを行ってます。