SRM651D1Med FoxConnection3

ちょっと珍しい解法

問題概要(原文(のコピー))

$2$ 次元平面の格子点に $N$ 匹のきつねがいる. $i$ 番のきつねがいる位置は $(x_i, y_i)$ である. きつねが連結になるように移動させるコストの最小値を求めよ.

考察

きつねの数は $6$ 匹と少ない.きつねの並べ方をdfsなどで全探索しよう.

次にどのきつねがどこに行くかを全探索しよう.これも高々 $6$ 匹なので,全て試せる.

すると最後はこの並びをどこに置くかだけである.まず $x$ 座標, $y$ 座標は独立である.

この問題は数直線上にいる $N$ 匹のきつねをどこに集めるのが最適か?という問題になる.これの答えは中央値である.

計算量は謎.

ソースコード

using System;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using Debug = System.Diagnostics.Debug;
using StringBuilder = System.Text.StringBuilder;
public class FoxConnection3
{
    public long minimalSteps(int[] x, int[] y)
    {
        dic = new SortedDictionary<ComparableList<Pair<int, int>>, long>();
        N = x.Length;
        X = x; Y = y;
        var ans = f(1, new ComparableList<Pair<int, int>>() { new Pair<int, int>(0, 0) });
        Debug.WriteLine(cnt);
        return ans;
    }
    int N;
    int[] X, Y;
    int[] dx = { 1, -1, 0, 0 };
    int[] dy = { 0, 0, -1, 1 };
    int cnt = 0;
    SortedDictionary<ComparableList<Pair<int, int>>, long> dic;
    public long f(int cur, ComparableList<Pair<int, int>> p)
    {
        {
            long res;
            if (dic.TryGetValue(p, out res))
                return res;
        }
        var min = long.MaxValue;
        if (cur == N)
        {
            //Debug.WriteLine(p.AsJoinedString());
            var a = Enumerate(N, x => x);
            do
            {
                min = Math.Min(min, g(a, p));
            } while (MathEx.NextPermutation(a, 0, N));
            cnt++;
        }
        else
        {
            for (int i = 0; i < p.Count; i++)
            {
                for (int d = 0; d < 4; d++)
                {
                    var np = new Pair<int, int>(p[i].x + dx[d], p[i].y + dy[d]);
                    if (np.y < 0) continue;
                    var ok = true;
                    for (int j = 0; j < p.Count; j++)
                        if (p[j].CompareTo(np) == 0) ok = false;
                    if (ok)
                    {
                        p.Add(np);
                        p.Sort();
                        min = Math.Min(f(cur + 1, p), min);
                        p.Remove(np);
                    }
                }
            }
        }
        var key = new ComparableList<Pair<int, int>>();
        for (int k = 0; k < p.Count; k++)
        {
            key.Add(new Pair<int, int>(p[k].x, p[k].y));
            dic[key] = min;
        }
        return min;

    }
    long g(int[] a, ComparableList<Pair<int, int>> p)
    {
        //Debug.WriteLine(p.AsJoinedString());
        long val = 0;
        {
            var xs = new long[N];
            for (int i = 0; i < N; i++)
                xs[i] = X[i] - p[a[i]].x;
            Array.Sort(xs);
            var x = N % 2 == 1 ? xs[N / 2] : (xs[(N - 1) / 2] + xs[N / 2]) / 2;
            for (int i = 0; i < N; i++)
                val += Math.Abs(xs[i] - x);
        }
        {
            var xs = new long[N];
            for (int i = 0; i < N; i++)
                xs[i] = Y[i] - p[a[i]].y;
            Array.Sort(xs);
            var x = N % 2 == 1 ? xs[N / 2] : (xs[(N - 1) / 2] + xs[N / 2]) / 2;
            for (int i = 0; i < N; i++)
                val += Math.Abs(xs[i] - x);
        }
        return val;
    }
    static public T[] Enumerate<T>(int n, Func<int, T> f) { var a = new T[n]; for (int i = 0; i < n; ++i) a[i] = f(i); return a; }
}
// CUT begin
public class Tester: AbstractTester
{
    static public T[] Enumerate<T>(int n, Func<int, T> f) { var a = new T[n]; for (int i = 0; i < n; ++i) a[i] = f(i); return a; }
    public Random rand = new Random(0);
    public Tester()
    {
    }
}
// CUT end


#region Compair
static public class Pair
{
    static public Pair<FT, ST> Create<FT, ST>(FT f, ST s)
        where FT : IComparable<FT>
        where ST : IComparable<ST>
    { return new Pair<FT, ST>(f, s); }
    static public Pair<FT, ST> Min<FT, ST>(Pair<FT, ST> p, Pair<FT, ST> q)
        where FT : IComparable<FT>
        where ST : IComparable<ST>
    { return (p.CompareTo(q) <= 0) ? p : q; }
    static public Pair<FT, ST> Max<FT, ST>(Pair<FT, ST> p, Pair<FT, ST> q)
        where FT : IComparable<FT>
        where ST : IComparable<ST>
    { return (p.CompareTo(q) >= 0) ? p : q; }
}
public struct Pair<FT, ST>: IComparable<Pair<FT, ST>>
    where FT : IComparable<FT>
    where ST : IComparable<ST>
{
    public FT x;
    public ST y;
    public Pair(FT f, ST s) : this() { x = f; y = s; }

    public int CompareTo(Pair<FT, ST> other)
    {
        var cmp = x.CompareTo(other.x);
        return cmp != 0 ? cmp : y.CompareTo(other.y);
    }
    public override string ToString() { return string.Format("{0} {1}", x, y); }
}
#endregion

#region ComparableList
public class ComparableList<T>: List<T>, IComparable<ComparableList<T>> where T : IComparable<T>
{
    public int CompareTo(ComparableList<T> other)
    {
        var k = Math.Min(Count, other.Count);
        for (int i = 0; i < k; i++)
        {
            var cmp = this[i].CompareTo(other[i]);
            if (cmp != 0) return cmp;
        }
        return Count.CompareTo(other.Count);
    }
}
#endregion

#region next_permutation
static public partial class MathEx
{

    static public bool NextPermutation<T>(this T[] array, int first, int last) where T : IComparable<T>
    {
        if (first == last)
            return false;
        var i = last;
        if (--i == first)
            return false;
        while (true)
        {
            var ii = i--;
            if (array[i].CompareTo(array[ii]) < 0)
            {
                var j = last;
                while (array[i].CompareTo(array[--j]) >= 0) { }
                var temp = array[i];
                array[i] = array[j];
                array[j] = temp;
                Array.Reverse(array, ii, last - ii);
                return true;
            }
            if (i == first)
            {
                Array.Reverse(array, first, last - first);
                return false;
            }
        }
    }

}
#endregion

コメント