AtCoderのPAST
前のPASTの問題へ
第19回PAST K 隣接禁止
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("5 2");
WillReturn.Add("1 2");
WillReturn.Add("2 3");
WillReturn.Add("1 4");
WillReturn.Add("2 5");
WillReturn.Add("3 1 4 1 5");
//9
}
else if (InputPattern == "Input2") {
WillReturn.Add("10 6");
WillReturn.Add("7 3");
WillReturn.Add("3 8");
WillReturn.Add("5 1");
WillReturn.Add("3 9");
WillReturn.Add("2 5");
WillReturn.Add("6 1");
WillReturn.Add("5 4");
WillReturn.Add("10 7");
WillReturn.Add("7 1");
WillReturn.Add("1 3 10 6 7 9 2 2 10 4");
//34
}
else if (InputPattern == "Input3") {
WillReturn.Add("10 6");
WillReturn.Add("2 10");
WillReturn.Add("1 10");
WillReturn.Add("7 4");
WillReturn.Add("8 9");
WillReturn.Add("8 7");
WillReturn.Add("4 3");
WillReturn.Add("1 4");
WillReturn.Add("6 7");
WillReturn.Add("5 3");
WillReturn.Add("2 5 1 2 3 6 2 9 9 7");
//-1
}
else {
string wkStr;
while ((wkStr = Console.ReadLine()) != null) WillReturn.Add(wkStr);
}
return WillReturn;
}
// 隣接リスト
static Dictionary<int, List<int>> mToNodeListDict = new Dictionary<int, List<int>>();
static void Main()
{
List<string> InputList = GetInputList();
int[] wkArr = { };
Action<string> SplitAct = pStr =>
wkArr = pStr.Split(' ').Select(pX => int.Parse(pX)).ToArray();
SplitAct(InputList[0]);
int NodeCnt = wkArr[0];
int NeedPaintCnt = wkArr[1];
int[] AArr = InputList.Last().Split(' ').Select(pX => int.Parse(pX)).ToArray();
foreach (string EachStr in InputList.Skip(1).Take(NodeCnt - 1)) {
SplitAct(EachStr);
int FromNode = wkArr[0];
int ToNode = wkArr[1];
if (mToNodeListDict.ContainsKey(FromNode) == false) {
mToNodeListDict[FromNode] = new List<int>();
}
if (mToNodeListDict.ContainsKey(ToNode) == false) {
mToNodeListDict[ToNode] = new List<int>();
}
mToNodeListDict[FromNode].Add(ToNode);
mToNodeListDict[ToNode].Add(FromNode);
}
List<DFSJyoutaiDef> DFSResult = ExecDFS(1);
DFSResult = DFSResult.OrderByDescending(pX => pX.Level).ToList();
var DPJyoutaiDictArr = new Dictionary<int, int>[NodeCnt + 1];
for (int I = 1; I <= NodeCnt; I++) {
DPJyoutaiDictArr[I] = new Dictionary<int, int>();
DPJyoutaiDef FirstJyoutai;
FirstJyoutai.CanPaint = 1;
FirstJyoutai.ChildPaintCnt = 0;
DPJyoutaiDictArr[I].Add(GetHash(FirstJyoutai), 0);
}
// DFSでのレベルの降順での、親ノードへの配る木DP
foreach (DFSJyoutaiDef EachJyoutai in DFSResult) {
int CurrNode = EachJyoutai.Node;
int ParentNode = EachJyoutai.ParentNode;
if (ParentNode == -1) continue;
foreach (var EachPair1 in DPJyoutaiDictArr[ParentNode].ToArray()) {
DPJyoutaiDef ParentJyoutai = GetDPJyoutai(EachPair1.Key);
foreach (var EachPair2 in DPJyoutaiDictArr[CurrNode]) {
DPJyoutaiDef CurrJyoutai = GetDPJyoutai(EachPair2.Key);
// 塗る場合
if (CurrJyoutai.CanPaint == 1) {
DPJyoutaiDef NewJyoutai1;
NewJyoutai1.CanPaint = 0;
NewJyoutai1.ChildPaintCnt = ParentJyoutai.ChildPaintCnt;
NewJyoutai1.ChildPaintCnt += CurrJyoutai.ChildPaintCnt;
NewJyoutai1.ChildPaintCnt++;
if (NewJyoutai1.ChildPaintCnt <= NeedPaintCnt) {
int NewVal = EachPair1.Value + EachPair2.Value;
NewVal += AArr[CurrNode - 1];
int CurrHash = GetHash(NewJyoutai1);
if (DPJyoutaiDictArr[ParentNode].ContainsKey(CurrHash) == false
|| DPJyoutaiDictArr[ParentNode][CurrHash] < NewVal) {
DPJyoutaiDictArr[ParentNode][CurrHash] = NewVal;
}
}
}
// 塗らない場合
DPJyoutaiDef NewJyoutai2;
NewJyoutai2.CanPaint = ParentJyoutai.CanPaint;
NewJyoutai2.ChildPaintCnt = ParentJyoutai.ChildPaintCnt;
NewJyoutai2.ChildPaintCnt += CurrJyoutai.ChildPaintCnt;
if (NewJyoutai2.ChildPaintCnt <= NeedPaintCnt) {
int NewVal = EachPair1.Value + EachPair2.Value;
int CurrHash = GetHash(NewJyoutai2);
if (DPJyoutaiDictArr[ParentNode].ContainsKey(CurrHash) == false
|| DPJyoutaiDictArr[ParentNode][CurrHash] < NewVal) {
DPJyoutaiDictArr[ParentNode][CurrHash] = NewVal;
}
}
}
}
}
var AnswerList = new List<int>();
foreach (var EachPair in DPJyoutaiDictArr[1]) {
DPJyoutaiDef CurrJyoutai = GetDPJyoutai(EachPair.Key);
if (CurrJyoutai.ChildPaintCnt == NeedPaintCnt) {
AnswerList.Add(EachPair.Value);
}
else if (CurrJyoutai.ChildPaintCnt == NeedPaintCnt - 1) {
if (CurrJyoutai.CanPaint == 1) {
// 根を塗る場合
AnswerList.Add(EachPair.Value + AArr[0]);
}
}
}
if (AnswerList.Count > 0) {
Console.WriteLine(AnswerList.Max());
}
else {
Console.WriteLine(-1);
}
}
struct DPJyoutaiDef
{
internal int CanPaint;
internal int ChildPaintCnt;
}
static int GetHash(DPJyoutaiDef pDPJyoutai)
{
return pDPJyoutai.ChildPaintCnt * 10 + pDPJyoutai.CanPaint;
}
static DPJyoutaiDef GetDPJyoutai(int pHash)
{
DPJyoutaiDef WillReturn;
WillReturn.CanPaint = pHash % 10;
WillReturn.ChildPaintCnt = pHash / 10;
return WillReturn;
}
struct DFSJyoutaiDef
{
internal int Node;
internal int ParentNode;
internal int Level;
}
static List<DFSJyoutaiDef> ExecDFS(int pRootNode)
{
var WillReturn = new List<DFSJyoutaiDef>();
var Stk = new Stack<DFSJyoutaiDef>();
DFSJyoutaiDef WillPush;
WillPush.Node = pRootNode;
WillPush.ParentNode = -1;
WillPush.Level = 1;
Stk.Push(WillPush);
var VisitedSet = new HashSet<int>();
VisitedSet.Add(pRootNode);
while (Stk.Count > 0) {
DFSJyoutaiDef Popped = Stk.Pop();
WillReturn.Add(Popped);
if (mToNodeListDict.ContainsKey(Popped.Node)) {
foreach (int EachToNode in mToNodeListDict[Popped.Node]) {
if (VisitedSet.Add(EachToNode)) {
WillPush.Node = EachToNode;
WillPush.ParentNode = Popped.Node;
WillPush.Level = Popped.Level + 1;
Stk.Push(WillPush);
}
}
}
}
return WillReturn;
}
}
解説
木DPで解いてます。
木DPの後で
根を塗る場合も、考慮する必要があります。