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

No.133 カードゲーム

■■■問題■■■

A君とB君はカードゲームが好きである。
カードゲームは1から2*Nまでの数字が1つずつ書かれた2*N枚のカードで行う。
A君とB君にはそれぞれN枚ずつカードが配られる。

ゲームは簡単である。
自由にカードを1枚出して数字の大きい方が1試合の勝ちである。
試合で1度出したカードは2度使えない。
全部でN試合し勝ち数が多いほうをゲームの勝ちとする。
A君とB君の勝ち数が等しければゲームは引き分けとなる。

カードはすでに配られた状態である。
N試合が終わったときに、A君がゲームに勝つ確率を計算せよ。
お互い思考性がなくランダムでカードを出すとする。

■■■入力■■■

N

A0 A1 ・・・ AN-1
B0 B1 ・・・ BN-1

Nは1 <= N <= 4の整数。
A0,A1 ・・・ AN-1 と B0,B1 ・・・ BN-1 は1から2*N までの数字を含む。
A0,A1 ・・・ AN-1 と B0,B1 ・・・ BN-1 の中に重複する数字は無い。

■■■出力■■■

A君の勝つ確率を1行で答えよ。絶対誤差は0.01まで認められる。
最後に改行を忘れずに。


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("2");
            WillReturn.Add("2 4");
            WillReturn.Add("1 3");
            //0.5
            //A君に2と4のカードが配られる。B君に1と3のカードが配られる。
            //試合は2試合でA君の出し方が2通り、
            //B君の出し方が2通りなので全部で4通りの結果になる。
            //A君が勝つのはそのうち2通りなので、確率は2/4=0.5である。
        }
        else if (InputPattern == "Input2") {
            WillReturn.Add("2");
            WillReturn.Add("3 4");
            WillReturn.Add("1 2");
            //1
            //どうやってもA君が勝つ
        }
        else if (InputPattern == "Input3") {
            WillReturn.Add("1");
            WillReturn.Add("1");
            WillReturn.Add("2");
            //0
            //どうやってもA君は勝てない
        }
        else if (InputPattern == "Input4") {
            WillReturn.Add("3");
            WillReturn.Add("6 2 3");
            WillReturn.Add("1 5 4");
            //0.666667
        }
        else {
            string wkStr;
            while ((wkStr = Console.ReadLine()) != null) WillReturn.Add(wkStr);
        }
        return WillReturn;
    }

    static void Main()
    {
        List<string> InputList = GetInputList();
        int[] AArr = InputList[1].Split(' ').Select(X => int.Parse(X)).ToArray();
        int[] BArr = InputList[2].Split(' ').Select(X => int.Parse(X)).ToArray();

        List<int[]> AJyunretu = DeriveJyunretu(AArr);
        List<int[]> BJyunretu = DeriveJyunretu(BArr);

        decimal TotalPatternCnt = AJyunretu.Count * BJyunretu.Count;
        decimal WinAPatternCnt = 0;

        foreach (int[] EachA in AJyunretu) {
            foreach (int[] EachB in BJyunretu) {
                int WinCnt = 0;
                int LoseCnt = 0;

                for (int I = 0; I <= AArr.GetUpperBound(0); I++) {
                    if (EachA[I] > EachB[I]) WinCnt++;
                    if (EachA[I] < EachB[I]) LoseCnt++;
                }
                if (WinCnt > LoseCnt) WinAPatternCnt++;
            }
        }
        Console.WriteLine(WinAPatternCnt / TotalPatternCnt);
    }

    struct JyoutaiDef
    {
        internal List<int> SelectedIndList;
    }

    //深さ優先探索で順列を列挙
    static List<int[]> DeriveJyunretu(int[] pArr)
    {
        var WillReturn = new List<int[]>();

        var stk = new Stack<JyoutaiDef>();
        JyoutaiDef WillPush;
        WillPush.SelectedIndList = new List<int>();
        stk.Push(WillPush);

        while (stk.Count > 0) {
            JyoutaiDef Popped = stk.Pop();

            //クリア判定
            if (Popped.SelectedIndList.Count == pArr.Length) {
                int[] wkArr = new int[pArr.Length];
                for (int I = 0; I <= wkArr.GetUpperBound(0); I++) {
                    wkArr[I] = pArr[Popped.SelectedIndList[I]];
                }
                WillReturn.Add(wkArr);
                continue;
            }

            for (int I = 0; I <= pArr.GetUpperBound(0); I++) {
                if (Popped.SelectedIndList.Contains(I)) continue;

                WillPush.SelectedIndList = new List<int>(Popped.SelectedIndList);
                WillPush.SelectedIndList.Add(I);
                stk.Push(WillPush);
            }
        }
        return WillReturn;
    }
}


解説

制約が緩いので、
Aのカードの全ての順列と
Bのカードの全ての順列を、列挙してます。