トップページに戻る    次の競技プログラミングの問題へ    前の競技プログラミングの問題へ

ABC-016-C 友達の友達

■■■問題■■■

高橋くんはSNSの管理者をしています。
このSNSではユーザ同士が友達という関係で繋がることができます。

高橋くんはそれぞれのユーザの「友達の友達」が何人いるかを調べることにしました。
友達関係が与えられるので、各ユーザの「友達の友達」の人数を求めてください。
ただし、自分自身や友達は、「友達の友達」に含みません。


■■■入力■■■

N M
A1 B1
A2 B2
・
・
・
AM BM

●1行目には、ユーザ数 N(1 <= N <= 10)
  と友達の組の数 M(0 <= M <= N×(N-1)/2) がスペース区切りで与えられる。
●各ユーザには1からNまでのユーザIDが割り当てられている。
●2行目からのM行では、
  友達関係にあるユーザのID Ai,Bi(1 <= Ai < Bi <= N) がスペース区切りで与えられる。
  ただし、i≠j ならば (Ai,Bi)≠(Aj,Bj) を満たす。

■■■出力■■■

各ユーザの友達の友達の人数をユーザIDの小さい順に1行ごと出力せよ。
出力の末尾には改行をつけること。


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

    struct ABPairInfoDef
    {
        internal int A;
        internal int B;
    }

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

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

        SplitAct(InputList[0]);
        int N = wkArr[0];

        var ABPairList = new List<ABPairInfoDef>();
        foreach (string EachStr in InputList.Skip(1)) {
            SplitAct(EachStr);
            ABPairInfoDef WillAdd;
            WillAdd.A = wkArr[0];
            WillAdd.B = wkArr[1];
            ABPairList.Add(WillAdd);
        }

        //ワーシャルフロイド法
        int[,] CostArr = new int[N + 1, N + 1];

        for (int I = 1; I <= N; I++) {
            for (int J = 1; J <= N; J++) {
                if (I == J) CostArr[I, J] = 0;
                else CostArr[I, J] = int.MaxValue / 2;
            }
        }

        foreach (ABPairInfoDef EachABPair in ABPairList) {
            CostArr[EachABPair.A, EachABPair.B] = 1;
            CostArr[EachABPair.B, EachABPair.A] = 1;
        }

        for (int K = 1; K <= N; K++) {
            for (int I = 1; I <= N; I++) {
                for (int J = 1; J <= N; J++) {
                    int Cost1 = CostArr[I, J];
                    int Cost2 = CostArr[I, K];
                    int Cost3 = CostArr[K, J];

                    if (Cost1 > Cost2 + Cost3)
                        CostArr[I, J] = Cost2 + Cost3;
                }
            }
        }

        for (int I = 1; I <= N; I++) {
            int Cost2Cnt = 0;
            for (int J = 1; J <= N; J++) {
                if (CostArr[I, J] == 2) Cost2Cnt++;
            }
            Console.WriteLine(Cost2Cnt);
        }
    }
}


解説

まず、ワーシャルフロイド法でノードの組み合わせごとの最短距離を求め、
それから、ノードごとに最短距離が2の訪問ノード数を数えてます。