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: Time Limit Exceeded)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
class Program
{

        private static int iN = 0;                                          // 順列の元の数
        private static int iK = 0;                                          // 順列の選ぶ数
        private static List<clsRute> lstRute = new List<clsRute>();         // 訪問順情報
        private static List<ClsAtoB> lstRoad = new List<ClsAtoB>();         // 道路情報
        private static List<ClsAtoB> lstShrt = new List<ClsAtoB>();         // 最短距離情報

    static void Main(string[] args)
    {
            // 入力
            string[] sS = Console.ReadLine().Trim().Split(' ');
            int iNN = int.Parse(sS[0]);                                     // 都市数
            int iMM = int.Parse(sS[1]);                                     // 道路数
            int iRR = int.Parse(sS[2]);                                     // 訪問地数
            List<int> lstDest = new List<int>();                            // 訪問地一覧
            sS = Console.ReadLine().Trim().Split(' ');
            for (int i = 0; i < sS.Length; i++) { lstDest.Add(int.Parse(sS[i])); }
            for (int i = 0; i < iMM; i++)
            {
                ClsAtoB oneUsr = new ClsAtoB();
                ClsAtoB oneUs2 = new ClsAtoB();
                sS = Console.ReadLine().Trim().Split(' ');
                oneUsr.iA = int.Parse(sS[0]);
                oneUsr.iB = int.Parse(sS[1]);
                oneUsr.iC = int.Parse(sS[2]);
                lstRoad.Add(oneUsr);                                        // 片一方からの情報
                oneUs2.iA = oneUsr.iB;
                oneUs2.iB = oneUsr.iA;
                oneUs2.iC = oneUsr.iC;
                lstRoad.Add(oneUs2);                                        // も一方からの情報
            }

            System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
            sw.Start();

            // 解析
            iN = iRR;
            iK = iRR;
            List<List<int>> lstCmp = new List<List<int>>();                 // 全順列(重複なし)
            List<int> lstTmp = new List<int>();                             // テンポラリ
            GetCom(lstCmp, lstTmp);                                         // 全順列取得(重複なし)
            for (int i = 0; i < lstCmp.Count; i++)                          // 全順列
            {
                for (int j = 0; j < lstCmp[i].Count - 1; j++)               // 全順列の1つ目の中から2つづつ使用
                {
                    int iA = lstDest[lstCmp[i][j]];                         // 最初の訪問地
                    int iB = lstDest[lstCmp[i][j + 1]];                     // 次  の訪問地
                    GetRuteData(i, iA, iB);                                 // 順列順に訪問順情報作成
                }
            }
            lstRute.Sort(delegate (clsRute mca1, clsRute mca2) { return (int)(mca1.iC - mca2.iC); });       // iCの昇順

            //出力
            Console.WriteLine("{0}", lstRute[0].iC.ToString().Trim());

            sw.Stop();
#if DEBUG
            Console.WriteLine();
            Console.WriteLine("{0}", sw.Elapsed.ToString());
            debugDisp();
            Console.WriteLine("続行するには何かキーを押してください．．．");
            Console.ReadKey();
#endif
    }

        // debug表示
        private static void debugDisp()
        {
            Console.WriteLine();
            Console.WriteLine("{0}", "lstRute".ToString().Trim());
            string sOut = "";
            for (int i = 0; i < lstRute.Count; i++)                         // 訪問順情報
            {
                if (i > 50) { break; }                                      // とりあえず桁が多いのでTop50
                sOut = " No=" + i.ToString("000") + " iC=" + lstRute[i].iC.ToString("000") + " lstOrdr=";
                for (int j = 0; j < lstRute[i].lstOrdr.Count; j++)          // 訪問順情報の都市訪問順
                {
                    sOut += lstRute[i].lstOrdr[j].ToString("000") + " ";
                }
                Console.WriteLine("{0}", sOut.ToString().Trim());
            }
            Console.WriteLine();
            Console.WriteLine("{0}", "lstShrt".ToString().Trim());
            Console.WriteLine("{0}", " No.   iA    iB   iC ".ToString().Trim());
            for (int i = 0; i < lstShrt.Count; i++)                         // 最短距離情報
            {
                sOut = i.ToString("000") + " " + lstShrt[i].iA.ToString("000") + " " + lstShrt[i].iB.ToString("000") + " " + lstShrt[i].iC.ToString("000");
                Console.WriteLine("{0}", sOut.ToString().Trim());
            }
            Console.WriteLine();
            Console.WriteLine("{0}", "lstRoad".ToString().Trim());
            Console.WriteLine("{0}", " No.   iA    iB   iC ".ToString().Trim());
            for (int i = 0; i < lstRoad.Count; i++)                         // 道路情報
            {
                sOut = i.ToString("000") + " " + lstRoad[i].iA.ToString("000") + " " + lstRoad[i].iB.ToString("000") + " " + lstRoad[i].iC.ToString("000");
                Console.WriteLine("{0}", sOut.ToString().Trim());
            }
        }

        // 訪問順情報取得
        private static void GetRuteData(int iCnt, int ia, int ib)
        {
            if (lstRute.Count <= iCnt) { lstRute.Add(new clsRute() { lstOrdr = new List<int>() { ia } }); }   // 新規の訪問順情報？
            Boolean bEx = false;                                            // 最短距離情報に存在フラグ
            for (int i = 0; i < lstShrt.Count; i++)                         // 最短距離情報内をチェック
            {
                if (lstShrt[i].iA == ia && lstShrt[i].iB == ib)
                {
                    lstRute[iCnt].lstOrdr.Add(ib);                          // 次の訪問地加算
                    lstRute[iCnt].iC += lstShrt[i].iC;                      // 最短距離加算
                    bEx = true;                                             // 最短距離情報に存在
                    break;
                }
            }
            if (!bEx)                                                       // 最短距離情報に存在しない場合は最短距離情報作成
            {
                int ic = 0;
                GetShrtData(ia, ib, ref ic);                                // 最短距離情報取得
                lstRute[iCnt].lstOrdr.Add(ib);                              // 次の訪問地加算
                lstRute[iCnt].iC += ic;                                     // 最短距離加算
            }
        }

        // 最短距離情報取得
        private static void GetShrtData(int ia, int ib, ref int ic)
        {
            int iDistNow = int.MaxValue;                                    // 距離
            Boolean bEx = false;                                            // 道路情報に存在フラグ
            for (int i = 0; i < lstRoad.Count; i++)                         // 道路情報内をチェック
            {
                if (lstRoad[i].iA == ia && lstRoad[i].iB == ib)
                {
                    iDistNow = lstRoad[i].iC;                               // 直接距離
                    bEx = true;                                             // 道路情報に存在
                    break;
                }
            }
            if (bEx)                                                        // 直接距離が存在する場合、他の都市経由でそれより最短距離があればそれを使用
            {
                GetShrtData2(true, ia, ib, ref iDistNow);
            }
            else                                                            // 直接距離が存在しない場合、他の都市経由で最短距離を使用
            {
                GetShrtData2(false, ia, ib, ref iDistNow);
            }
            ic = iDistNow;
            lstShrt.Add(new ClsAtoB() { iA = ia, iB = ib, iC = ic });       // 新しい最短距離情報 片一方からの情報
            lstShrt.Add(new ClsAtoB() { iA = ib, iB = ia, iC = ic });       // 新しい最短距離情報 も一方からの情報
        }

        // 最短距離情報取得その２
        private static void GetShrtData2(Boolean bSt, int ia, int ib, ref int iDistNow)
        {
            // iSt = 1: 最初だけ ia から ibの移動は除外
            // iSt = 2: 最初から ia から ibの移動も検索
            // 一度通った都市は除外

            List<int> lstDest = new List<int>();                                                                    // 引数のia都市から行ける都市一覧
            List<int> lstDist = new List<int>();                                                                    // 上記の都市までの距離
            List<int> lstPssd = new List<int>();                                                                    // 一度通った都市は除外
            for (int i = 0; i < lstRoad.Count; i++)                                                                 // 道路情報内をチェック
            {
                if (bSt)                                                                                            // ib以外
                {
                    if (lstRoad[i].iA == ia && lstRoad[i].iB != ib && !lstPssd.Contains(lstRoad[i].iB))             // 一度通った都市は除外 ibも除外
                    {
                        if (iDistNow > lstRoad[i].iC) { lstDist.Add(lstRoad[i].iC); lstDest.Add(lstRoad[i].iB); }   // 今までの距離以内でないと意味がない
                    }
                }
                else                                                                                                // ibも考慮
                {
                    if (lstRoad[i].iA == ia && !lstPssd.Contains(lstRoad[i].iB))                                    // 一度通った都市は除外
                    {
                        if (iDistNow > lstRoad[i].iC) { lstDist.Add(lstRoad[i].iC); lstDest.Add(lstRoad[i].iB); }   // 今までの距離以内でないと意味がない
                    }

                }
            }
            lstPssd.Add(ia);                                                                                        // 一度通った都市は除外
            if (lstDest.Count > 0)                                                                                  // 他の移動経路がある
            {
                for (int j = 0; j < lstDest.Count; j++)                                                             // 他の経路
                {
                    if (lstDest[j] == ib)                                                                           // 今回の最短距離判別先の目的都市
                    {
                        if (iDistNow > lstDist[j]) { iDistNow = lstDist[j]; }                                       // 最短距離
                    }
                    else
                    {
                        GetShrtData3(lstDest[j], ib, ref iDistNow, lstDist[j], lstPssd);                            // 他の経路
                    }
                }
            }
        }

        // 最短距離情報取得その３
        private static void GetShrtData3(int ia, int ib, ref int iDistNow, int iDistNew, List<int> lstPssd)
        {
            List<int> lstDest = new List<int>();                                                                    // 引数のia都市から行ける都市一覧
            List<int> lstDist = new List<int>();                                                                    // 上記の都市までの距離
            for (int i = 0; i < lstRoad.Count; i++)                                                                 // 道路情報内をチェック
            {
                if (lstRoad[i].iA == ia && !lstPssd.Contains(lstRoad[i].iB))
                {
                    if (iDistNow > iDistNew + lstRoad[i].iC) { lstDist.Add(iDistNew + lstRoad[i].iC); lstDest.Add(lstRoad[i].iB); }   // 今までの距離以内でないと意味がない
                }
            }
            List<int> lstPssdNew = new List<int>();                                                                 // 一度通った都市は除外
            lstPssdNew.AddRange(lstPssd);
            lstPssdNew.Add(ia);                                                                                        // 一度通った都市は除外
            if (lstDest.Count > 0)                                                                                  // 他の移動経路がある
            {
                for (int j = 0; j < lstDest.Count; j++)                                                             // 他の経路
                {
                    if (lstDest[j] == ib)                                                                           // 今回の最短距離判別先の目的都市
                    {
                        if (iDistNow > lstDist[j]) { iDistNow = lstDist[j]; }                                       // 最短距離
                    }
                    else
                    {
                        GetShrtData3(lstDest[j], ib, ref iDistNow, lstDist[j], lstPssdNew);                         // 他の経路
                    }
                }
            }
        }

        // 重複なし順列
        private static void GetCom(List<List<int>> lstCmp, List<int> lstTmp)
        {
            for (int j = 0; j < iN; j++)
            {
                int iKn = 1;
                List<int> lstTm2 = new List<int>();
                lstTm2.AddRange(lstTmp);
                lstTm2.Add(j);
                GetCo2(lstCmp, lstTm2, iKn);
            }
        }

        // 順列2
        private static void GetCo2(List<List<int>> lstCmp, List<int> lstTmp, int iKn)
        {
            if (iKn == iK) { lstCmp.Add(lstTmp); return; }
            for (int j = 0; j < iN; j++)
            {
                if (lstTmp.Contains(j)) { continue; }
                List<int> lstTm2 = new List<int>();
                lstTm2.AddRange(lstTmp);
                lstTm2.Add(j);
                GetCo2(lstCmp, lstTm2, iKn + 1);
            }
        }

        private class clsRute                   // 訪問順情報
        {
            public List<int> lstOrdr { get; set; } = new List<int>();   // 訪問順
            public int       iC      { get; set; } = 0;                 // 総距離
        }

        private class ClsAtoB                   // 道路情報or最短距離情報
        {
            public int iA { get; set; } = 0;                            // 一方
            public int iB { get; set; } = 0;                            // 一方
            public int iC { get; set; } = 0;                            // 距離or最短距離
        }

}