競技プログラミングの鉄則    次の問題へ    前の問題へ

B23 Traveling Salesman Problem


問題へのリンク


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

    static int mN;
    static int mAllBitOn;
    static int UB;

    struct XYInfoDef
    {
        internal int X;
        internal int Y;
    }
    static List<XYInfoDef> mXYInfoList = new List<XYInfoDef>();

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

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

        mN = int.Parse(InputList[0]);
        mAllBitOn = (1 << mN) - 1;

        foreach (string EachStr in InputList.Skip(1)) {
            SplitAct(EachStr);
            XYInfoDef WillAdd;
            WillAdd.X = wkArr[0];
            WillAdd.Y = wkArr[1];
            mXYInfoList.Add(WillAdd);
        }
        UB = mXYInfoList.Count - 1;

        var AnswerKouho = new List<double>();
        for (int I = 0; I <= UB; I++) {
            AnswerKouho.Add(ExecTSP(I));
        }
        Console.WriteLine(AnswerKouho.Min());
    }

    // 開始位置を引数としてTSPの最小コストを返す
    static double ExecTSP(int pStaInd)
    {
        // コスト[訪問済BitSet,現在位置] なインラインDP表
        double?[,] DPArr = new double?[mAllBitOn + 1, UB + 1];

        DPArr[0, pStaInd] = 0;

        for (int I = 0; I <= mAllBitOn; I++) {
            for (int J = 0; J <= UB; J++) {
                if (DPArr[I, J].HasValue == false) continue;

                for (int K = 0; K <= UB; K++) {
                    int CurrBit = (1 << K);
                    if ((I & CurrBit) > 0) continue;

                    int NewI = I + CurrBit;

                    // 最後の移動先は、ゴールノードの必要あり
                    if (NewI != mAllBitOn && K == pStaInd) continue;

                    double NewVal = DPArr[I, J].Value;
                    int CurrX = mXYInfoList[J].X;
                    int CurrY = mXYInfoList[J].Y;
                    int NextX = mXYInfoList[K].X;
                    int NextY = mXYInfoList[K].Y;

                    int XDiff = CurrX - NextX;
                    int YDiff = CurrY - NextY;
                    NewVal += Math.Sqrt(XDiff * XDiff + YDiff * YDiff);

                    if (DPArr[NewI, K].HasValue) {
                        if (DPArr[NewI, K] <= NewVal) {
                            continue;
                        }
                    }
                    DPArr[NewI, K] = NewVal;
                }
            }
        }
        return DPArr[mAllBitOn, pStaInd].Value;
    }
}


解説

TSPなのでBitDPで解いてます。