トップページに戻る
次の競技プログラミングの問題へ
前の競技プログラミングの問題へ
第2回 CodeIQプロコン 3問目 復讐
■■■問題■■■
いくつかの狙撃目標地点について、各地点間の移動コストが与えられます。
たとえば次のような4地点について、1→3→2→4または4→2→3→1と移動すると移動コストは7となり、
他のどの移動方法よりも低コストになります。
このような、すべての地点を移動する、移動コストの最小値を求めてください。
最初の地点は任意です。最初の地点への移動コストは考えないものとします。
■■■入力■■■
標準入力から、1行目に整数値N (4 <= N <= 10)が与えられます。
2行目以降に、N個の整数値が半角スペースによって区切られたN行のデータ、つまりN*N個の整数値が与えられます。
これはNつの点同士の、移動にかかる時間を行列の形式で表したものです。
A→BとB→Aは同じ移動コストですので、左上から右下への対角線(0の部分)に対して必ず対称になっています。
■■■出力■■■
標準出力に、最小の移動コスト(整数値のみ)を出力してください。
C#のソース
using System;
using System.Collections.Generic;
using System.Linq;
class Program
{
static string InputPattern = "Input1";
static List<string> GetInputList()
{
var WillReturn = new List<string>();
if (InputPattern == "Input1") {
WillReturn.Add("4");
WillReturn.Add("0 3 2 8");
WillReturn.Add("3 0 1 4");
WillReturn.Add("2 1 0 5");
WillReturn.Add("8 4 5 0");
//7
}
else {
string wkStr;
while ((wkStr = Console.ReadLine()) != null) WillReturn.Add(wkStr);
}
return WillReturn;
}
struct JyoutaiDef
{
internal int CurrPos;
internal int SumCost;
internal bool[] IsVisitedArr;
//internal string Path;
}
static void Main()
{
List<string> InputList = GetInputList();
int N = int.Parse(InputList[0]);
//隣接行列で枝を表現
int[,] RinsetuGyouretu = new int[N, N];
int UB = N - 1;
for (int I = 0; I <= UB; I++) {
int[] wkArr = InputList[I + 1].Split(' ').Select(X => int.Parse(X)).ToArray();
for (int J = 0; J <= UB; J++) {
RinsetuGyouretu[J, I] = wkArr[J];
}
}
var stk = new Stack<JyoutaiDef>();
JyoutaiDef WillPush;
for (int I = 0; I <= UB; I++) {
WillPush.CurrPos = I;
WillPush.SumCost = 0;
WillPush.IsVisitedArr = new bool[UB + 1];
WillPush.IsVisitedArr[I] = true;
//WillPush.Path = I.ToString();
stk.Push(WillPush);
}
int AnswerCost = int.MaxValue;
//string AnswerPath = "";
while (stk.Count > 0) {
JyoutaiDef Popped = stk.Pop();
//クリア判定
if (Array.TrueForAll(Popped.IsVisitedArr, X => X)) {
if (AnswerCost > Popped.SumCost) {
AnswerCost = Popped.SumCost;
//AnswerPath = Popped.Path;
}
continue;
}
for (int I = 0; I <= UB; I++) {
if (Popped.IsVisitedArr[I])
continue;
WillPush.CurrPos = I;
WillPush.SumCost = Popped.SumCost + RinsetuGyouretu[Popped.CurrPos, I];
//下限値枝切り
if (WillPush.SumCost >= AnswerCost) {
continue;
}
WillPush.IsVisitedArr = (bool[])Popped.IsVisitedArr.Clone();
WillPush.IsVisitedArr[I] = true;
//WillPush.Path = Popped.Path + "," + I.ToString();
stk.Push(WillPush);
}
}
Console.WriteLine(AnswerCost);
}
}
解説
深さ優先探索を使ってます。