AtCoderのPAST    次のPASTの問題へ    前のPASTの問題へ

第8回PAST M バランス


問題へのリンク


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 2");
            WillReturn.Add("2 3 1");
            //1
            //1
            //0
        }
        else if (InputPattern == "Input2") {
            WillReturn.Add("3 3");
            WillReturn.Add("1 2 0");
            WillReturn.Add("2 3 0");
            WillReturn.Add("1 3 2");
            //-1
        }
        else {
            string wkStr;
            while ((wkStr = Console.ReadLine()) != null) WillReturn.Add(wkStr);
        }
        return WillReturn;
    }

    static long mNodeCnt;

    struct EdgeInfoDef
    {
        internal long ToNode;
        internal long SumVal;
    }
    static Dictionary<long, List<EdgeInfoDef>> mEdgeInfoListDict = new Dictionary<long, List<EdgeInfoDef>>();

    static void Main()
    {
        List<string> InputList = GetInputList();

        long[] wkArr = { };
        Action<string> SplitAct = pStr =>
            wkArr = pStr.Split(' ').Select(pX => long.Parse(pX)).ToArray();

        SplitAct(InputList[0]);
        mNodeCnt = wkArr[0];

        foreach (string EachStr in InputList.Skip(1)) {
            SplitAct(EachStr);
            long A = wkArr[0];
            long B = wkArr[1];
            long C = wkArr[2];

            Action<long, long, long> AddEdgeAct = (pFromNode, pToNode, pSumVal) =>
            {
                if (mEdgeInfoListDict.ContainsKey(pFromNode) == false) {
                    mEdgeInfoListDict[pFromNode] = new List<EdgeInfoDef>();
                }
                EdgeInfoDef WillAdd;
                WillAdd.ToNode = pToNode;
                WillAdd.SumVal = pSumVal;
                mEdgeInfoListDict[pFromNode].Add(WillAdd);
            };
            AddEdgeAct(A, B, C);
            AddEdgeAct(B, A, C);
        }

        for (long I = 1; I <= mNodeCnt; I++) {
            mNodeValInfoListDict[I] = new List<NodeValInfoDef>();
        }

        // ノード1からDFSを行う
        ExecDFS1();

        // Xの符号が同じものが複数あったら実現不可
        foreach (var EachPair in mNodeValInfoListDict) {
            var XSet = new HashSet<long>();
            foreach (NodeValInfoDef EachNodeValInfo in EachPair.Value) {
                if (XSet.Add(EachNodeValInfo.X) == false) {
                    Console.WriteLine(-1);
                    return;
                }
            }
        }

        // Xの値が特定可能な場合
        foreach (var EachPair in mNodeValInfoListDict) {
            if (EachPair.Value.Count == 2) {
                long Uhen = 0;
                foreach (NodeValInfoDef EachNodeValInfo in EachPair.Value) {
                    if (EachNodeValInfo.X == 1) {
                        Uhen -= EachNodeValInfo.Teisuu;
                    }
                    if (EachNodeValInfo.X == -1) {
                        Uhen += EachNodeValInfo.Teisuu;
                    }
                }
                if (Uhen % 2 == 1) {
                    Console.WriteLine(-1);
                    return;
                }
                if (Uhen < 0) {
                    Console.WriteLine(-1);
                    return;
                }
                long XVal = Uhen / 2;

                // DFSを行い、十分性の確認
                Dictionary<long, long> ResultDict1;
                bool Result1 = ExecDFS2(1, XVal, out ResultDict1);
                if (Result1) {
                    foreach (var EachValInfo in ResultDict1.OrderBy(pX => pX.Key)) {
                        Console.WriteLine(EachValInfo.Value);
                    }
                    return;
                }
                Console.WriteLine(-1);
                return;
            }
        }

        // Xの範囲が特定できる場合
        var XList1 = new List<long>();
        var XList2 = new List<long>();

        foreach (var EachPair in mNodeValInfoListDict) {
            NodeValInfoDef CurrNodeValInfo = EachPair.Value[0];
            if (CurrNodeValInfo.X == 1) {
                XList1.Add(CurrNodeValInfo.Teisuu * (-1));
            }
            if (CurrNodeValInfo.X == -1) {
                XList2.Add(CurrNodeValInfo.Teisuu);
            }
        }

        long RangeMin = XList1.Max();
        long RangeMax = XList2.Min();

        if (RangeMax < 0) {
            Console.WriteLine(-1);
            return;
        }

        long AnswerX = Math.Max(0, RangeMin);

        // DFSを行い、十分性の確認
        Dictionary<long, long> ResultDict2;
        bool Result2 = ExecDFS2(1, AnswerX, out ResultDict2);
        if (Result2) {
            foreach (var EachValInfo in ResultDict2.OrderBy(pX => pX.Key)) {
                Console.WriteLine(EachValInfo.Value);
            }
            return;
        }
        Console.WriteLine(-1);
        return;
    }

    // ノード1からDFSを行う
    static void ExecDFS1()
    {
        var Stk = new Stack<JyoutaiDef1>();
        JyoutaiDef1 WillPush;
        WillPush.CurrNode = 1;
        Stk.Push(WillPush);

        NodeValInfoDef FirstNodeValInfo;
        FirstNodeValInfo.X = 1;
        FirstNodeValInfo.Teisuu = 0;
        mNodeValInfoListDict[1].Add(FirstNodeValInfo);

        var UsedEdgeSet = new HashSet<long>();
        while (Stk.Count > 0) {
            JyoutaiDef1 Popped = Stk.Pop();

            long CurrNode = Popped.CurrNode;
            foreach (EdgeInfoDef EachEdgeInfo in mEdgeInfoListDict[CurrNode]) {
                long FromNode = CurrNode;
                long ToNode = EachEdgeInfo.ToNode;
                long EdgeHash = GetEdgeHash(FromNode, ToNode);
                if (UsedEdgeSet.Add(EdgeHash) == false) {
                    continue;
                }

                NodeValInfoDef CurrNodeValInfo = mNodeValInfoListDict[CurrNode][0];

                NodeValInfoDef ToNodeValInfo;
                ToNodeValInfo.X = -CurrNodeValInfo.X;
                ToNodeValInfo.Teisuu = EachEdgeInfo.SumVal - CurrNodeValInfo.Teisuu;
                mNodeValInfoListDict[ToNode].Add(ToNodeValInfo);

                // 重複はremove
                var CurrList = mNodeValInfoListDict[ToNode];
                for (int I = CurrList.Count - 1; 0 <= I; I--) {
                    for (int J = 0; J <= I - 1; J++) {
                        if (CurrList[I].X == CurrList[J].X
                         && CurrList[I].Teisuu == CurrList[J].Teisuu) {
                            CurrList.RemoveAt(I);
                            break;
                        }
                    }
                }

                WillPush.CurrNode = ToNode;
                Stk.Push(WillPush);
            }
        }
    }

    struct NodeValInfoDef
    {
        internal long X; // Xの係数
        internal long Teisuu; // 定数
    }
    static Dictionary<long, List<NodeValInfoDef>> mNodeValInfoListDict =
        new Dictionary<long, List<NodeValInfoDef>>();

    struct JyoutaiDef1
    {
        internal long CurrNode;
    }

    // DFSを行い、全てのノードを0以上にできるかを判定
    static bool ExecDFS2(long pStaNode, long pStaVal, out Dictionary<long, long> pResultDict)
    {
        // 値[ノード]なDict
        pResultDict = new Dictionary<long, long>();
        pResultDict[pStaNode] = pStaVal;

        var Stk = new Stack<JyoutaiDef2>();
        JyoutaiDef2 WillPush;
        WillPush.CurrNode = pStaNode;
        WillPush.CurrVal = pStaVal;
        Stk.Push(WillPush);

        var UsedEdgeSet = new HashSet<long>();
        while (Stk.Count > 0) {
            JyoutaiDef2 Popped = Stk.Pop();

            long CurrNode = Popped.CurrNode;
            foreach (EdgeInfoDef EachEdgeInfo in mEdgeInfoListDict[CurrNode]) {
                long FromNode = CurrNode;
                long ToNode = EachEdgeInfo.ToNode;
                long EdgeHash = GetEdgeHash(FromNode, ToNode);
                if (UsedEdgeSet.Add(EdgeHash) == false) {
                    continue;
                }

                long NewVal = EachEdgeInfo.SumVal - Popped.CurrVal;
                if (NewVal < 0) return false;
                if (pResultDict.ContainsKey(ToNode)) {
                    if (pResultDict[ToNode] != NewVal) {
                        return false;
                    }
                }
                pResultDict[ToNode] = NewVal;

                WillPush.CurrNode = ToNode;
                WillPush.CurrVal = NewVal;
                Stk.Push(WillPush);
            }
        }
        return true;
    }

    struct JyoutaiDef2
    {
        internal long CurrNode;
        internal long CurrVal;
    }

    // 枝のハッシュ値
    static long GetEdgeHash(long pNode1, long pNode2)
    {
        long MinNode = Math.Min(pNode1, pNode2);
        long MaxNode = Math.Max(pNode1, pNode2);
        return MaxNode * 1000000 + MinNode;
    }
}


解説

ノード1をXとすると
枝の値から、隣接ノードの値は
 X+定数か
-X+定数
の形で表現できます。

なのでノード1をXとして、DFSしてます。