トップページに戻る    次のC#のサンプルへ    前のC#のサンプルへ

8-14 最小全域木問題

問題

最小全域木を求める。

問題


答え


ソース

using System;
using System.Collections.Generic;
using System.Linq;

class Program
{
    struct GraphInfoDef
    {
        internal char FromPos;
        internal char ToPos;
        internal int Cost;
    }

    static void Main()
    {
        GraphInfoDef[] GraphArr = new GraphInfoDef[9];
        GraphArr[0].FromPos = 'A'; GraphArr[0].ToPos = 'B'; GraphArr[0].Cost = 5;
        GraphArr[1].FromPos = 'A'; GraphArr[1].ToPos = 'C'; GraphArr[1].Cost = 2;
        GraphArr[2].FromPos = 'B'; GraphArr[2].ToPos = 'C'; GraphArr[2].Cost = 4;
        GraphArr[3].FromPos = 'B'; GraphArr[3].ToPos = 'D'; GraphArr[3].Cost = 2;
        GraphArr[4].FromPos = 'C'; GraphArr[4].ToPos = 'D'; GraphArr[4].Cost = 3;
        GraphArr[5].FromPos = 'C'; GraphArr[5].ToPos = 'E'; GraphArr[5].Cost = 2;
        GraphArr[6].FromPos = 'D'; GraphArr[6].ToPos = 'E'; GraphArr[6].Cost = 6;
        GraphArr[7].FromPos = 'D'; GraphArr[7].ToPos = 'F'; GraphArr[7].Cost = 6;
        GraphArr[8].FromPos = 'E'; GraphArr[8].ToPos = 'F'; GraphArr[8].Cost = 4;

        //プリム法で最小全域木を求める
        var PriorityQueue = new CppPriorityQueue();

        //到達済ノードのSet
        var ToutatuNodeSet = new HashSet<char>();

        //Enqueue処理
        Action<char> EnqueueAct = pConnNode =>
        {
            ToutatuNodeSet.Add(pConnNode);
            foreach (GraphInfoDef EachGraphInfo in GraphArr) {
                if (EachGraphInfo.FromPos == pConnNode) {
                    //到達済ノードならContinue
                    if (ToutatuNodeSet.Contains(EachGraphInfo.ToPos)) continue;

                    PriorityQueue.Enqueue(EachGraphInfo.ToPos, EachGraphInfo.Cost);
                }
                if (EachGraphInfo.ToPos == pConnNode) {
                    //到達済ノードならContinue
                    if (ToutatuNodeSet.Contains(EachGraphInfo.FromPos)) continue;

                    PriorityQueue.Enqueue(EachGraphInfo.FromPos, EachGraphInfo.Cost);
                }
            }
        };
        EnqueueAct('A');
        int SumCost = 0;

        while (PriorityQueue.Count > 0) {
            PriorityQueueItemDef Dequeued = PriorityQueue.Dequeue();

            //到達済ノードならContinue
            if (ToutatuNodeSet.Contains(Dequeued.ToNode)) continue;

            SumCost += Dequeued.EdaCost;
            EnqueueAct(Dequeued.ToNode);

            Console.WriteLine("{0}への枝を追加。コスト={1}", Dequeued.ToNode, Dequeued.EdaCost);
        }
        Console.WriteLine("最小全域木のコスト合計={0}", SumCost);
    }
}

//PriorityQueueもどき
struct PriorityQueueItemDef
{
    internal char ToNode;
    internal int EdaCost;
}
class CppPriorityQueue
{
    private List<PriorityQueueItemDef> mItemList = new List<PriorityQueueItemDef>();

    internal int Count { get { return mItemList.Count; } }

    internal void Enqueue(char pToNode, int pEdaCost)
    {
        mItemList.Add(new PriorityQueueItemDef() { ToNode = pToNode, EdaCost = pEdaCost });
    }

    internal PriorityQueueItemDef Dequeue()
    {
        int wkInd = 0;
        for (int I = 1; I <= mItemList.Count - 1; I++) {
            //コストが最小の枝を返す
            if (mItemList[I].EdaCost < mItemList[wkInd].EdaCost)
                wkInd = I;
        }
        PriorityQueueItemDef WillRetun = mItemList[wkInd];
        mItemList.RemoveAt(wkInd);
        return WillRetun;
    }
}


実行結果

Cへの枝を追加。コスト=2
Eへの枝を追加。コスト=2
Dへの枝を追加。コスト=3
Bへの枝を追加。コスト=2
Fへの枝を追加。コスト=4
最小全域木のコスト合計=13


解説

プリム法のアリゴリズムを使ってます。