Problem:
Score : 400 points

Problem Statement

There are N towns in the State of Atcoder, connected by M bidirectional roads.

The i-th road connects Town A_i and B_i and has a length of C_i.

Joisino is visiting R towns in the state, r_1,r_2,..,r_R (not necessarily in this order).

She will fly to the first town she visits, and fly back from the last town she visits, but for the rest of the trip she will have to travel by road.

If she visits the towns in the order that minimizes the distance traveled by road, what will that distance be?

Constraints

2≤N≤200

1≤M≤N×(N-1)/2

2≤R≤min(8,N) (min(8,N) is the smaller of 8 and N.)

r_i≠r_j (i≠j)

1≤A_i,B_i≤N, A_i≠B_i

(A_i,B_i)≠(A_j,B_j),(A_i,B_i)≠(B_j,A_j) (i≠j)

1≤C_i≤100000

Every town can be reached from every town by road.

All input values are integers.

Input

Input is given from Standard Input in the following format:

N M R
r_1 ... r_R
A_1 B_1 C_1
:
A_M B_M C_M

Output

Print the distance traveled by road if Joisino visits the towns in the order that minimizes it.

Sample Input 1

3 3 3
1 2 3
1 2 1
2 3 1
3 1 4

Sample Output 1

2

For example, if she visits the towns in the order of 1, 2, 3, the distance traveled will be 2, which is the minimum possible.

Sample Input 2

3 3 2
1 3
2 3 2
1 3 6
1 2 2

Sample Output 2

4

The shortest distance between Towns 1 and 3 is 4. Thus, whether she visits Town 1 or 3 first, the distance traveled will be 4.

Sample Input 3

4 6 3
2 3 4
1 2 4
2 3 3
4 3 1
1 4 1
4 2 2
3 1 6

Sample Output 3

3

Solution in C# (Mono 4.6.2.0) (judge verdict: Runtime Error)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using ContestLibraryD073;
//解法は合ってるはずだがなぜかWA
namespace ABC_D
{
    class D073
    {
        static void Main(string[] args)
        {
            int[] a = Console.ReadLine().Split(' ').Select(z => int.Parse(z)).ToArray();
            int N = a[0], M = a[1], R = a[2];

            int[] r = Console.ReadLine().Split(' ').Select(z => int.Parse(z)).ToArray();

            Graph g = new Graph(N, false, true);
            for (int i = 0; i < M; i++)
            {
                int[] e = Console.ReadLine().Split(' ').Select(z => int.Parse(z)).ToArray();
                g.AddEdge(e[0], e[1], e[2]);
            }

            int[,] prev;
            long[,] distance = g.WarshallFloydLong(out prev);

            List<string> slist = MakePermutation(R);
            List<int[]> list = new List<int[]>();
            foreach (string s in slist)
            {
                int[] pr = s.ToCharArray().Select(x => r[x - '0' - 1]).ToArray();
                list.Add(pr);
            }

            long min = long.MaxValue;
            foreach(int[] arr in list)
            {
                long sum = 0;
                for (int i = 1; i < arr.Length; i++)
                {
                    int tid = arr[i - 1];
                    int nid = arr[i];
                    sum += (long)distance[tid - 1, nid - 1];
                }
                if (sum < min) min = sum;
            }
            Console.WriteLine(min);
        }

        //9までの順列を全列挙
        static List<string> MakePermutation(int n)
        {
            List<List<int>> current = new List<List<int>>();
            current.Add(new List<int> { 1 });
            for (int i = 2; i <= n; i++)
            {
                List<List<int>> next = new List<List<int>>();
                List<int> newList = new List<int>();

                foreach (List<int> list in current)
                {
                    for (int j = 0; j <= list.Count; j++)
                    {
                        List<int> ilist = new List<int>(list);
                        ilist.Insert(j, i);
                        next.Add(ilist);
                    }
                }
                current = next;
            }
            List<string> arr = current.Select(x => string.Join("", x)).ToList();
            arr.Sort();
            return arr;
        }



    }
}
namespace ContestLibraryD073
{

    class Graph
    {
        public bool UseMatrix { get; set; }
        //private bool idZeroStart;
        public List<Vertex> Vertices { get; }
        public List<Edge> Edges { get; }
        public double[,] Matrix { get; private set; }
        public bool IsDirectedGraph { get; }

        //idは1,2,...,N
        public Graph(int N, bool isDirectedGraph = false, bool useMatrix = false)
        {
            IsDirectedGraph = isDirectedGraph;
            Vertices = new List<Vertex>();
            Edges = new List<Edge>();

            if (useMatrix) Matrix = new double[N, N];

            for (int i = 0; i < N; i++)
            {
                int id = i + 1;
                Vertex n = new Vertex(id);
                Vertices.Add(n);
            }
        }

        //隣接行列方式でのセットアップ
        public void SetAdjancencyMatrix(double[,] matrix)
        {
            Matrix = matrix;

            if (matrix.GetLength(0) != Vertices.Count || matrix.GetLength(1) != Vertices.Count)
            {
                throw new Exception("Invalid Matrix Size");
            }

            for (int i = 0; i < Vertices.Count; i++)
            {
                Vertex vertexL = Vertices[i];
                for (int j = 0; j < Vertices.Count; j++)
                {
                    if (i > j && !IsDirectedGraph) continue;
                    if (matrix[i, j] != double.PositiveInfinity)
                    {
                        Vertex vertexR = Vertices[j];
                        Edge edge = new Edge(vertexL, vertexR, matrix[i, j], IsDirectedGraph);
                        Edges.Add(edge);
                    }
                }
            }

        }


        //隣接リスト方式でのセットアップ
        public void AddAdjacencyList(int idVertex, Dictionary<int, double> adjDictionary)
        {
            int indexL = idVertex - 1;
            Vertex vertexL = Vertices[indexL];

            foreach (var v in adjDictionary)
            {
                int idR = v.Key;
                double weight = v.Value;
                int indexR = idR - 1;
                Vertex vertexR = Vertices[indexR];
                Edge edge = new Edge(vertexL, vertexR, weight, IsDirectedGraph);
                Edges.Add(edge);
                if (Matrix != null)
                {
                    Matrix[indexL, indexR] = weight;
                    if (!IsDirectedGraph) Matrix[indexR, indexL] = weight;
                }
            }
        }
        public void AddAdjacencyList(int idVertex, List<int> adjList)
        {
            Dictionary<int, double> dic = new Dictionary<int, double>();
            foreach (int x in adjList)
            {
                dic.Add(x, 1);
            }
            AddAdjacencyList(idVertex, dic);
        }

        //辺単位でのセットアップ
        public void AddEdge(int idL, int idR, int weight = 1)
        {
            int indexL = idL - 1;
            int indexR = idR - 1;

            Vertex vertexL = Vertices[indexL];
            Vertex vertexR = Vertices[indexR];
            Edge edge = new Edge(vertexL, vertexR, weight, IsDirectedGraph);
            Edges.Add(edge);
            if (Matrix != null)
            {
                Matrix[indexL, indexR] = weight;
                if (!IsDirectedGraph) Matrix[indexR, indexL] = weight;
            }
        }


        //開始点を指定し、幅優先探索で到達できる
        //各頂点に対応するステップ数（辺ウェイト考慮せず）と直近頂点IDのペアをDictionaryで出力
        public Dictionary<int, int[]> BreadthFirstSearch(int idS)
        {
            Dictionary<int, int[]> dic = new Dictionary<int, int[]>();
            int[] item = { 0, 0 };
            dic.Add(idS, item);
            int index = idS - 1;

            List<Vertex> nodes = new List<Vertex>();
            Vertex nodeStart = Vertices[index];
            nodeStart.Visited = true;
            nodes.Add(nodeStart);
            int depth = 1;
            while (nodes.Count > 0)
            {
                List<Vertex> nextNodes = new List<Vertex>();
                foreach (Vertex node in nodes)
                {
                    foreach (Vertex cn in node.ConnectedVertices)
                    {
                        if (!cn.Visited)
                        {
                            nextNodes.Add(cn);
                            cn.Visited = true;
                            int[] nitem = { depth, node.Id };
                            dic.Add(cn.Id, nitem);
                        }
                    }
                }
                nodes = nextNodes;
                depth++;
            }
            return dic;
        }

        //開始点を指定し、深さ優先探索
        //TimeFound(訪問時刻)とTimeProcessed(処理完了時刻)を出力
        public int DepthFirstSearch(int idS, int connectGraphNo = 1, int time = 0)
        {
            Stack<Vertex> stack = new Stack<Vertex>();
            int index = idS - 1;
            List<Vertex> nodes = new List<Vertex>();
            Vertex nodeStart = Vertices[index];
            nodeStart.Visited = true;

            stack.Push(nodeStart);
            nodeStart.TimeVisited = time;
            nodeStart.ConnectGraphNo = connectGraphNo;

            while (stack.Count > 0)
            {
                Vertex v = stack.Peek();

                if (v.IndexNextSearch >= v.ConnectedVertices.Count)
                {
                    time++;
                    v.TimeProcessed = time;
                    stack.Pop();
                }
                else
                {
                    Vertex vn = v.ConnectedVertices[v.IndexNextSearch];
                    if (!vn.Visited)
                    {
                        time++;
                        stack.Push(vn);
                        vn.Visited = true;
                        vn.TimeVisited = time;
                        vn.ConnectGraphNo = connectGraphNo;
                    }
                    v.IndexNextSearch++;
                }
            }
            return time;
        }

        //全頂点を探索
        public void DFS()
        {
            int time = 1;
            int connectNo = 1;
            int index = 0;
            while (index < Vertices.Count)
            {
                int id = index + 1;
                time = DepthFirstSearch(id, connectNo, time);

                while (index < Vertices.Count && Vertices[index].Visited) index++;
                connectNo++;
                time++;
            }
        }

        //二点間の最短経路を取得(幅優先探索の結果を利用)
        public List<Vertex> ShortestPath(int idS, int idT)
        {
            Dictionary<int, int[]> dic = BreadthFirstSearch(idS);
            List<int> plist = new List<int>();
            int p = idT;
            while (p != idS)
            {
                p = dic[p][1];
                plist.Add(p);
            }
            plist.Reverse();
            List<Vertex> vlist = new List<Vertex>();
            foreach (int id in plist)
            {
                Vertex vp = Vertices[id - 1];
                vlist.Add(vp);
            }
            Vertex vT = Vertices[idT - 1];
            vlist.Add(vT);
            return vlist;
        }


        //Prim法で最小全域木を作成し重みの総和を計算(PriorityQueueクラスを利用)
        //辺に着目するためO(m log(m))であまり早くないが殆どの場合十分と思われる
        public double MinimumSpanningTree()
        {
            //最初に選ぶ頂点は何でもよい
            Vertex v0 = Vertices[0];

            bool[] includedVertex = new bool[Vertices.Count + 1];
            double sumWeight = 0;

            //最小全域木に含まれるEdge
            List<Edge> mstEdges = new List<Edge>();
            //現在の木に隣接しているEdgeの優先度付きキュー
            PriorityQueue<Edge> pq = new PriorityQueue<Edge>();

            includedVertex[v0.Id] = true;
            foreach (Edge en in v0.ConnectedEdges)
            {
                pq.Enqueue(en, -en.Weight);
            }

            int counter = 1;
            while (counter < Vertices.Count)
            {
                Edge edge = pq.Dequeue();
                Vertex v;
                //既に両方の頂点が木に含まれているEdgeは除外（含むとループができてしまう)
                if (includedVertex[edge.VertexL.Id] && includedVertex[edge.VertexR.Id]) continue;
                else if (includedVertex[edge.VertexL.Id]) v = edge.VertexR;
                else v = edge.VertexL;
                mstEdges.Add(edge);
                sumWeight += edge.Weight;
                includedVertex[v.Id] = true;

                //新しく木に隣接するようになったEdgeをキューに追加
                foreach (Edge e1 in v.ConnectedEdges)
                {
                    if (includedVertex[e1.VertexL.Id] && includedVertex[e1.VertexR.Id]) continue;
                    pq.Enqueue(e1, -e1.Weight);
                }

                counter++;
            }

            return sumWeight;
        }

        //O((|V|+|E|)ln(|V|)
        public double[] Dijkstra(int idS)
        {
            double[] distances = Enumerable.Repeat(double.PositiveInfinity, Vertices.Count + 1).ToArray();
            int index = idS - 1;
            distances[idS] = 0;

            Vertex v0 = Vertices[index];

            PriorityQueue<Vertex> pq = new PriorityQueue<Vertex>();
            pq.Enqueue(v0, 0);

            while (pq.Count > 0)
            {
                Vertex v = pq.Dequeue();
                foreach (Edge e in v.ConnectedEdges)
                {
                    Vertex vn = e.VertexL == v ? e.VertexR : e.VertexL;
                    double distanceNew = distances[v.Id] + e.Weight;
                    if (distanceNew < distances[vn.Id])
                    {
                        distances[vn.Id] = distanceNew;
                        //distanceがより良い値に更新される時、
                        //同一のVertexが複数キューに入ることがあるが、
                        //先に入った（悪い方の）数値は必ず無視されるので問題ない
                        pq.Enqueue(vn, -distances[vn.Id]);
                    }
                }
            }


            return distances;
        }

        //負閉路を含む場合戻り値False
        //有向グラフ限定 重みマイナスを許容,ネガティブループ検出　O(|V||E|)
        public bool BellmanFord(int idS, out double[] distances)
        {
            distances = Enumerable.Repeat(double.PositiveInfinity, Vertices.Count + 1).ToArray();
            int index = idS - 1;
            distances[idS] = 0;

            for (int i = 0; i < Vertices.Count - 1; i++)
            {
                foreach (Edge e in Edges)
                {
                    double dn = distances[e.VertexL.Id] + e.Weight;
                    if (dn < distances[e.VertexR.Id])
                    {
                        distances[e.VertexR.Id] = dn;
                    }
                }
            }

            foreach (Edge e in Edges)
            {
                if (distances[e.VertexR.Id] > distances[e.VertexL.Id] + e.Weight)
                {
                    return false;
                }
            }
            return true;
        }

        //全点対最短経路（ワ―シャル・フロイト） 要matrix O(N^3)
        public double[,] WarshallFloyd(out int[,] predecessorMatrix)
        {
            int N = Vertices.Count;
            double[,] d = (double[,])Matrix.Clone();

            int[,] p = new int[N, N]; //先行点行列
            for (int i = 0; i < N; i++)
            {
                for (int j = 0; j < N; j++)
                {
                    if (d[i, j] != double.PositiveInfinity && i != j)
                    {
                        p[i, j] = i + 1;
                    }
                }
            }

            for (int k = 0; k < N; k++)
            {
                double[,] dn = new double[N, N];
                int[,] pn = new int[N, N];
                for (int i = 0; i < N; i++)
                {
                    for (int j = 0; j < N; j++)
                    {
                        if (i == j) continue;
                        //kを経由することで改善する場合
                        if (d[i, j] > d[i, k] + d[k, j])
                        {
                            dn[i, j] = d[i, k] + d[k, j];
                            pn[i, j] = p[k, j];
                        }
                        else
                        {
                            dn[i, j] = d[i, j];
                            pn[i, j] = p[i, j];
                        }
                    }
                }
                d = dn; p = pn;
            }
            predecessorMatrix = p;
            return d;
        }

        //全点対最短経路（ワ―シャル・フロイト） 要matrix O(N^3)
        public long[,] WarshallFloydLong(out int[,] predecessorMatrix)
        {
            int N = Vertices.Count;
            long[,] d = (long[,])Matrix.Clone();

            int[,] p = new int[N, N]; //先行点行列
            for (int i = 0; i < N; i++)
            {
                for (int j = 0; j < N; j++)
                {
                    if (d[i, j] != double.PositiveInfinity && i != j)
                    {
                        p[i, j] = i + 1;
                    }
                }
            }

            for (int k = 0; k < N; k++)
            {
                long[,] dn = new long[N, N];
                int[,] pn = new int[N, N];
                for (int i = 0; i < N; i++)
                {
                    for (int j = 0; j < N; j++)
                    {
                        if (i == j) continue;
                        //kを経由することで改善する場合
                        if (d[i, j] > d[i, k] + d[k, j])
                        {
                            dn[i, j] = d[i, k] + d[k, j];
                            pn[i, j] = p[k, j];
                        }
                        else
                        {
                            dn[i, j] = d[i, j];
                            pn[i, j] = p[i, j];
                        }
                    }
                }
                d = dn; p = pn;
            }
            predecessorMatrix = p;
            return d;
        }



    }

    class Vertex
    {
        public int Id { get; }
        public List<Edge> ConnectedEdges { get; private set; }
        public List<Vertex> ConnectedVertices { get; private set; }
        public bool Visited { get; set; }
        public int TimeVisited { get; set; }
        public int TimeProcessed { get; set; }
        public int IndexNextSearch { get; set; } //次に探索するVertex番号
        public int ConnectGraphNo { get; set; } //連結している頂点は同じ番号


        public Vertex(int id)
        {
            Id = id;
            ConnectedEdges = new List<Edge>();
            ConnectedVertices = new List<Vertex>();
        }


    }

    class Edge
    {
        public Vertex VertexL { get; }
        public Vertex VertexR { get; }
        public double Weight { get; }

        public Edge(Vertex vertexL, Vertex vertexR, double weight, bool isDirected)
        {
            VertexL = vertexL;
            VertexR = vertexR;
            vertexL.ConnectedEdges.Add(this);
            vertexL.ConnectedVertices.Add(vertexR);
            if (!isDirected)
            {
                vertexR.ConnectedEdges.Add(this);
                vertexR.ConnectedVertices.Add(vertexL);
            }
            Weight = weight;
        }
    }

    //優先度付きキュー（実装はヒープ)
    class PriorityQueue<T>
    {
        private List<HeapNode> heap = new List<HeapNode>();

        public int Count
        {
            get
            {
                return heap.Count;
            }
        }

        public void Enqueue(T item, double priority)
        {
            HeapNode node = new HeapNode(item, priority);
            heap.Add(node);

            int index = heap.Count - 1;

            while (index > 0)
            {
                int indexParent = (index - 1) / 2;
                HeapNode parent = heap[indexParent];
                if (priority > parent.Priority)
                {
                    Swap(index, indexParent);
                    index = indexParent;
                }
                else
                {
                    break;
                }
            }
        }

        public T Dequeue()
        {
            if (heap.Count == 0)
            {
                throw new Exception("No item in priorityQueue");
            }

            T item = heap[0].Node;
            heap[0] = heap[heap.Count - 1];
            heap.RemoveAt(heap.Count - 1);
            if (heap.Count > 0)
            {
                HeapNode node = heap[0];
                int index = 0;
                while (true)
                {
                    int indexL = 2 * index + 1;
                    int indexR = 2 * index + 2;
                    if (indexL >= heap.Count) //子なし(Leaf)
                    {
                        break;
                    }
                    else //子が存在
                    {
                        HeapNode childBetter = heap[indexL];
                        int indexBetter = indexL;
                        if (indexR < heap.Count && heap[indexL].Priority < heap[indexR].Priority)
                        {
                            childBetter = heap[indexR];
                            indexBetter = indexR;
                        }

                        if (node.Priority < childBetter.Priority)
                        {
                            Swap(index, indexBetter);
                            //node = childBetter; 参照なのでスワップで自動的に子を参照してる
                            index = indexBetter;
                        }
                        else
                        {
                            break;
                        }
                    }
                }
            }
            return item;
        }

        public T Peek()
        {
            if (heap.Count == 0)
            {
                throw new Exception("No item in priorityQueue");
            }
            return heap[0].Node;
        }

        private void Swap(int i, int j)
        {
            HeapNode hn = heap[i];
            heap[i] = heap[j];
            heap[j] = hn;
        }


        class HeapNode
        {
            public T Node { get; }
            public double Priority { get; }
            public HeapNode(T item, double priority)
            {
                Node = item;
                Priority = priority;
            }
        }

    }


}