Submission #68709741


Source Code Expand

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Formats.Asn1;
using System.Linq;
using System.Runtime;
using System.Runtime.CompilerServices;
using System.Text;

public class Solution
{
    public const int TIME_LIMIT = 1700;
    private static Random random = new Random(0);
    public static void Main()
    {
        int[] inputs = Console.ReadLine().Split(' ').Select(int.Parse).ToArray();
        Stopwatch sw = Stopwatch.StartNew();
        Board.Size = inputs[0];
        int m = inputs[1];
        int k = inputs[2];
        Board.InitGrid();
        Board board = new Board();
        board.Robots = Enumerable.Range(0, m).Select(i => new Robot { ID = i }).ToList();
        board.Waxed = new bool[Board.Size * Board.Size];
        Robot.RobotActions = Enumerable.Range(0, m).Select(i => new int[k]).ToArray();
        foreach (Robot r in board.Robots)
        {
            inputs = Console.ReadLine().Split(' ').Select(int.Parse).ToArray();
            r.Location = Board.Grid[inputs[1], inputs[0]];
            board.Waxed[r.Location.ID] = true;
        }
        board.WaxedCount = board.Waxed.Count(b => b);

        for (int y = 0; y < Board.Size; y++)
        {
            string line = Console.ReadLine();
            for (int x = 0; x < line.Length; x++)
            {
                if (line[x] == '1')
                {
                    Board.Grid[x, y].Neighbors[0] = Board.Grid[x, y];
                    Board.Grid[x + 1, y].Neighbors[2] = Board.Grid[x + 1, y];
                }
            }
        }
        for (int y = 0; y < Board.Size - 1; y++)
        {
            string line = Console.ReadLine();
            for (int x = 0; x < line.Length; x++)
            {
                if (line[x] == '1')
                {
                    Board.Grid[x, y].Neighbors[1] = Board.Grid[x, y];
                    Board.Grid[x, y + 1].Neighbors[3] = Board.Grid[x, y + 1];
                }
            }
        }
        Board.InitDistances();

        string actionString = "RDLUS";
        InitActions(board);
        Board solution = WaxBoard(board, null);
        Console.Error.WriteLine("initial solution: " + solution.Depth + " @" + sw.ElapsedMilliseconds + " ms");
        HashSet<Board> revertedTo = new();
        while (sw.ElapsedMilliseconds < TIME_LIMIT)
        {
            Board prev = solution.Parent;
            Cell lastFill = null;
            foreach (Cell c in Board.Grid)
            {
                if (!prev.Waxed[c.ID]) lastFill = c;
            }
            Board b = board;
            while (prev.Parent != null)
            {
                if (prev.Robots.Any(r => r.Location.Neighbors.Contains(lastFill))) b = prev;
                prev = prev.Parent;
            }
            if (!revertedTo.Add(b))
            {
                b = board;
                for (int i = 0; i < 5; i++) b = board.Expand().OrderBy(b => random.NextDouble()).First();
            }
            else if (b != board) b = b.Expand().First(e => e.Waxed[lastFill.ID]);
            Console.Error.WriteLine(sw.ElapsedMilliseconds + "ms: revert to " + b.Depth);
            Board refill = WaxBoard(b, sw);
            Console.Error.WriteLine("refill length: " + refill?.Depth);
            if (refill != null && refill.Depth < solution.Depth)
            {
                Console.Error.WriteLine("shorten: " + solution.Depth + " => " + refill.Depth);
                solution = refill;
            }
        }

        // try to fill last cell with different action
        bool improved = true;
        while (improved)
        {
            improved = false;
            Board prev = solution.Parent;
            Cell lastFill = null;
            foreach (Cell c in Board.Grid)
            {
                if (!prev.Waxed[c.ID]) lastFill = c;
            }
            List<Board> candidates = new();
            List<Board> path = new();
            while (prev.Parent != null)
            {
                path.Add(prev);
                if (prev.Robots.Any(r => r.Location.Neighbors.Contains(lastFill))) candidates.Add(prev);
                prev = prev.Parent;
            }
            path.Add(prev);
            path.Reverse();
            foreach (Board c in candidates.Reverse<Board>())
            {
                foreach (Robot r in c.Robots.Where(ro => ro.Location.Neighbors.Contains(lastFill)))
                {
                    int a1 = r.Location.Neighbors.ToList().IndexOf(lastFill);
                    int a2 = lastFill.Neighbors.ToList().IndexOf(r.Location);
                    List<int> a1Cand = Enumerable.Range(0, k).Where(i => r.Actions[i] == a1).ToList();
                    List<int> a2Cand = Enumerable.Range(0, k).Where(i => r.Actions[i] == a2).ToList();
                    foreach (int a1Take in a2Cand)
                    {
                        foreach (int a2Take in a1Cand)
                        {
                            Board inserted = InsertAction(c, path, r, a1Take, a2Take);
                            if (inserted != null && inserted.Depth < solution.Depth)
                            {
                                Console.Error.WriteLine("postprecessing: " + solution.Depth + " => " + inserted.Depth);
                                improved = true;
                                solution = inserted;
                                goto hasImproved;
                            }
                        }
                    }
                    List<int> empty = Enumerable.Range(0, k).Where(i => r.Actions[i] == 4).ToList();
                    for (int e = 0; e + 1 < empty.Count; e += 2)
                    {
                        r.Actions[empty[e]] = a1;
                        r.Actions[empty[e + 1]] = a2;
                        Board inserted = InsertAction(c, path, r, empty[e], empty[e + 1]);
                        if (inserted != null && inserted.Depth < solution.Depth)
                        {
                            Console.Error.WriteLine("postprecessing: " + solution.Depth + " => " + inserted.Depth);
                            improved = true;
                            solution = inserted;
                            goto hasImproved;
                        }
                        else
                        {
                            r.Actions[empty[e]] = 4;
                            r.Actions[empty[e + 1]] = 4;
                        }
                    }
                }
            }
        hasImproved:;
        }

        for (int actionId = 0; actionId < k; actionId++)
        {
            Console.WriteLine(string.Join(" ", solution.Robots.Select(r => actionString[r.Actions[actionId]])));
        }
        List<int> actions = new();
        while (solution.Parent != null)
        {
            actions.Add(solution.Action);
            solution = solution.Parent;
        }
        actions.Reverse();
        foreach (int a in actions) Console.WriteLine(a);
    }

    private static Board InsertAction(Board board, List<Board> path, Robot r, int action1, int action2)
    {
        int index = path.IndexOf(board);
        Board result = path[0];
        for (int i = 1; i <= index; i++) result = new Board(result, path[i].Action);
        result = new Board(result, action1);
        result = new Board(result, action2);
        for (int i = index + 1; i < path.Count; i++) result = new Board(result, path[i].Action);
        if (result.WaxedCount != Board.Size * Board.Size) return null;
        while (result.Parent.WaxedCount == Board.Size * Board.Size) result = result.Parent;
        return result;
    }

    private static Board WaxBoard(Board board, Stopwatch sw)
    {
        List<Board> beam = new() { board };
        for (int depth = 1; sw == null || sw.ElapsedMilliseconds < TIME_LIMIT; depth++)
        {
            beam = beam.SelectMany(b => b.Expand()).OrderByDescending(b => 0.01 * random.NextDouble() + b.Score()).Take(3).ToList();
            if (beam[0].WaxedCount == Board.Size * Board.Size) return beam[0];
        }
        return null;
    }

    private static void InitActions(Board board)
    {
        foreach (Robot r in board.Robots)
        {
            while (r.Actions.Distinct().Count() < 4)
            {
                for (int i = 0; i < r.Actions.Length; i++) r.Actions[i] = Math.Min(i, 4);
                //for (int i = 0; i < r.Actions.Length; i++) r.Actions[i] = random.Next(4);// Math.Min(i, 4);
            }
        }
    }
}

public class Board
{
    public static int Size;
    public List<Robot> Robots = new();
    public static Cell[,] Grid;
    public bool[] Waxed;
    public int WaxedCount;
    public Board Parent;
    public int Action;
    public int Depth;

    public Board() { }
    public Board(Board parent, int action)
    {
        this.Parent = parent;
        this.Action = action;
        this.Depth = parent.Depth + 1;
        this.WaxedCount = parent.WaxedCount;
        this.Waxed = parent.Waxed.ToArray();
        this.Robots = parent.Robots.Select(r => new Robot(r, action)).ToList();
        foreach (Robot r in Robots)
        {
            if (!Waxed[r.Location.ID])
            {
                Waxed[r.Location.ID] = true;
                WaxedCount++;
            }
        }
    }

    public static void InitGrid()
    {
        Grid = new Cell[Board.Size, Board.Size];
        for (int x = 0; x < Board.Size; x++)
        {
            for (int y = 0; y < Board.Size; y++)
            {
                Grid[x, y] = new Cell(x, y);
            }
        }
        foreach (Cell cell in Grid) cell.InitNeighbors(Grid);
    }

    public static void InitDistances()
    {
        foreach (Cell cell in Grid) cell.InitDistances();
    }

    public IEnumerable<Board> Expand()
    {
        for (int i = 0; i < 4; i++)
        {
            yield return new Board(this, i);
        }
    }

    public double Score()
    {
        double result = 1e6 * WaxedCount;
        result += 0.3 * Robots.Select(r => r.Location).Distinct().Count();
        int closest = 1000;
        foreach (Cell c in Board.Grid)
        {
            if (!Waxed[c.ID])
            {
                closest = Math.Min(closest, Robots.Min(r => r.Location.Dist[c.ID]));
                int openNeighbors = c.DistinctNeighbors.Count(n => !Waxed[n.ID]);
                if (openNeighbors == 0) result -= 3;
                else if (openNeighbors == 1) result -= 1;
            }
        }
        foreach (Robot r in Robots)
        {
            int unwaxedNeighbors = r.Location.DistinctNeighbors.Count(n => !Waxed[n.ID]);
            if (unwaxedNeighbors > 0) result += 0.01 * (4 - unwaxedNeighbors);
        }
        result -= closest;
        return result;
    }
}

public class Robot
{
    public int ID;
    public Cell Location;
    public static int[][] RobotActions;
    public int[] Actions => RobotActions[ID];

    public Robot() { }
    public Robot(Robot r, int action)
    {
        this.ID = r.ID;
        this.Location = r.Location.Neighbors[Actions[action]];
    }

    public override string ToString() => ID + ": " + Location;
}

public class Cell
{
    public int X;
    public int Y;
    public int ID => X + Y * Board.Size;
    public Cell[] Neighbors = new Cell[5];
    public Cell[] DistinctNeighbors;
    public int[] Dist;

    public Cell(int x, int y)
    {
        X = x;
        Y = y;
    }

    private static int[] dx = { 1, 0, -1, 0, 0 };
    private static int[] dy = { 0, 1, 0, -1, 0 };
    public void InitNeighbors(Cell[,] grid)
    {
        for (int dir = 0; dir < dx.Length; dir++)
        {
            int x_ = X + dx[dir];
            int y_ = Y + dy[dir];
            if (x_ < 0 || x_ >= Board.Size || y_ < 0 || y_ >= Board.Size) Neighbors[dir] = this;
            else Neighbors[dir] = grid[x_, y_];
        }
        DistinctNeighbors = Neighbors.Where(n => n != this).Distinct().ToArray();
    }

    public void InitDistances()
    {
        Dist = new int[Board.Size * Board.Size];
        Array.Fill(Dist, 10000);
        Dist[ID] = 0;
        Queue<Cell> queue = new Queue<Cell>();
        queue.Enqueue(this);
        while (queue.Count > 0)
        {
            Cell c = queue.Dequeue();
            foreach (Cell n in c.Neighbors)
            {
                if (Dist[n.ID] < 10000) continue;
                Dist[n.ID] = 1 + Dist[c.ID];
                queue.Enqueue(n);
            }
        }
    }

    public override string ToString() => X + "/" + Y;
}

Submission Info

Submission Time
Task A - Single Controller Multiple Robots
User eulerscheZahl
Language C# 11.0 (.NET 7.0.7)
Score 354455
Code Size 12864 Byte
Status AC
Exec Time 1774 ms
Memory 63920 KiB

Judge Result

Set Name test_ALL
Score / Max Score 354455 / 405000
Status
AC × 150
Set Name Test Cases
test_ALL test_0000.txt, test_0001.txt, test_0002.txt, test_0003.txt, test_0004.txt, test_0005.txt, test_0006.txt, test_0007.txt, test_0008.txt, test_0009.txt, test_0010.txt, test_0011.txt, test_0012.txt, test_0013.txt, test_0014.txt, test_0015.txt, test_0016.txt, test_0017.txt, test_0018.txt, test_0019.txt, test_0020.txt, test_0021.txt, test_0022.txt, test_0023.txt, test_0024.txt, test_0025.txt, test_0026.txt, test_0027.txt, test_0028.txt, test_0029.txt, test_0030.txt, test_0031.txt, test_0032.txt, test_0033.txt, test_0034.txt, test_0035.txt, test_0036.txt, test_0037.txt, test_0038.txt, test_0039.txt, test_0040.txt, test_0041.txt, test_0042.txt, test_0043.txt, test_0044.txt, test_0045.txt, test_0046.txt, test_0047.txt, test_0048.txt, test_0049.txt, test_0050.txt, test_0051.txt, test_0052.txt, test_0053.txt, test_0054.txt, test_0055.txt, test_0056.txt, test_0057.txt, test_0058.txt, test_0059.txt, test_0060.txt, test_0061.txt, test_0062.txt, test_0063.txt, test_0064.txt, test_0065.txt, test_0066.txt, test_0067.txt, test_0068.txt, test_0069.txt, test_0070.txt, test_0071.txt, test_0072.txt, test_0073.txt, test_0074.txt, test_0075.txt, test_0076.txt, test_0077.txt, test_0078.txt, test_0079.txt, test_0080.txt, test_0081.txt, test_0082.txt, test_0083.txt, test_0084.txt, test_0085.txt, test_0086.txt, test_0087.txt, test_0088.txt, test_0089.txt, test_0090.txt, test_0091.txt, test_0092.txt, test_0093.txt, test_0094.txt, test_0095.txt, test_0096.txt, test_0097.txt, test_0098.txt, test_0099.txt, test_0100.txt, test_0101.txt, test_0102.txt, test_0103.txt, test_0104.txt, test_0105.txt, test_0106.txt, test_0107.txt, test_0108.txt, test_0109.txt, test_0110.txt, test_0111.txt, test_0112.txt, test_0113.txt, test_0114.txt, test_0115.txt, test_0116.txt, test_0117.txt, test_0118.txt, test_0119.txt, test_0120.txt, test_0121.txt, test_0122.txt, test_0123.txt, test_0124.txt, test_0125.txt, test_0126.txt, test_0127.txt, test_0128.txt, test_0129.txt, test_0130.txt, test_0131.txt, test_0132.txt, test_0133.txt, test_0134.txt, test_0135.txt, test_0136.txt, test_0137.txt, test_0138.txt, test_0139.txt, test_0140.txt, test_0141.txt, test_0142.txt, test_0143.txt, test_0144.txt, test_0145.txt, test_0146.txt, test_0147.txt, test_0148.txt, test_0149.txt
Case Name Status Exec Time Memory
test_0000.txt AC 1759 ms 62908 KiB
test_0001.txt AC 1764 ms 62964 KiB
test_0002.txt AC 1760 ms 62772 KiB
test_0003.txt AC 1769 ms 62956 KiB
test_0004.txt AC 1759 ms 63108 KiB
test_0005.txt AC 1764 ms 62876 KiB
test_0006.txt AC 1764 ms 62748 KiB
test_0007.txt AC 1763 ms 62856 KiB
test_0008.txt AC 1763 ms 63016 KiB
test_0009.txt AC 1756 ms 62872 KiB
test_0010.txt AC 1763 ms 63260 KiB
test_0011.txt AC 1774 ms 62636 KiB
test_0012.txt AC 1772 ms 62624 KiB
test_0013.txt AC 1762 ms 63092 KiB
test_0014.txt AC 1762 ms 63028 KiB
test_0015.txt AC 1757 ms 63340 KiB
test_0016.txt AC 1756 ms 62732 KiB
test_0017.txt AC 1756 ms 63248 KiB
test_0018.txt AC 1770 ms 63212 KiB
test_0019.txt AC 1764 ms 62668 KiB
test_0020.txt AC 1758 ms 62876 KiB
test_0021.txt AC 1762 ms 62920 KiB
test_0022.txt AC 1757 ms 63244 KiB
test_0023.txt AC 1764 ms 62948 KiB
test_0024.txt AC 1760 ms 63132 KiB
test_0025.txt AC 1763 ms 62788 KiB
test_0026.txt AC 1762 ms 62600 KiB
test_0027.txt AC 1760 ms 63284 KiB
test_0028.txt AC 1759 ms 63356 KiB
test_0029.txt AC 1768 ms 63108 KiB
test_0030.txt AC 1761 ms 62984 KiB
test_0031.txt AC 1766 ms 63000 KiB
test_0032.txt AC 1757 ms 62604 KiB
test_0033.txt AC 1760 ms 63388 KiB
test_0034.txt AC 1757 ms 62692 KiB
test_0035.txt AC 1764 ms 62676 KiB
test_0036.txt AC 1760 ms 62652 KiB
test_0037.txt AC 1767 ms 63156 KiB
test_0038.txt AC 1752 ms 62788 KiB
test_0039.txt AC 1752 ms 62736 KiB
test_0040.txt AC 1764 ms 63432 KiB
test_0041.txt AC 1761 ms 62948 KiB
test_0042.txt AC 1759 ms 62604 KiB
test_0043.txt AC 1756 ms 62884 KiB
test_0044.txt AC 1762 ms 62708 KiB
test_0045.txt AC 1762 ms 62956 KiB
test_0046.txt AC 1756 ms 62860 KiB
test_0047.txt AC 1766 ms 62648 KiB
test_0048.txt AC 1759 ms 63136 KiB
test_0049.txt AC 1760 ms 63920 KiB
test_0050.txt AC 1761 ms 63184 KiB
test_0051.txt AC 1761 ms 63256 KiB
test_0052.txt AC 1770 ms 62948 KiB
test_0053.txt AC 1766 ms 62564 KiB
test_0054.txt AC 1760 ms 62656 KiB
test_0055.txt AC 1762 ms 63192 KiB
test_0056.txt AC 1765 ms 62688 KiB
test_0057.txt AC 1760 ms 63068 KiB
test_0058.txt AC 1762 ms 63000 KiB
test_0059.txt AC 1753 ms 62704 KiB
test_0060.txt AC 1772 ms 63276 KiB
test_0061.txt AC 1761 ms 62764 KiB
test_0062.txt AC 1759 ms 62764 KiB
test_0063.txt AC 1764 ms 63052 KiB
test_0064.txt AC 1762 ms 63076 KiB
test_0065.txt AC 1758 ms 63000 KiB
test_0066.txt AC 1753 ms 63428 KiB
test_0067.txt AC 1757 ms 63064 KiB
test_0068.txt AC 1762 ms 62824 KiB
test_0069.txt AC 1766 ms 62788 KiB
test_0070.txt AC 1763 ms 62884 KiB
test_0071.txt AC 1760 ms 63092 KiB
test_0072.txt AC 1762 ms 62776 KiB
test_0073.txt AC 1763 ms 63152 KiB
test_0074.txt AC 1761 ms 62960 KiB
test_0075.txt AC 1760 ms 63076 KiB
test_0076.txt AC 1757 ms 63304 KiB
test_0077.txt AC 1759 ms 63236 KiB
test_0078.txt AC 1761 ms 62912 KiB
test_0079.txt AC 1754 ms 63176 KiB
test_0080.txt AC 1764 ms 62872 KiB
test_0081.txt AC 1763 ms 63048 KiB
test_0082.txt AC 1763 ms 63512 KiB
test_0083.txt AC 1759 ms 63164 KiB
test_0084.txt AC 1760 ms 63088 KiB
test_0085.txt AC 1763 ms 62712 KiB
test_0086.txt AC 1762 ms 62700 KiB
test_0087.txt AC 1757 ms 62964 KiB
test_0088.txt AC 1760 ms 63148 KiB
test_0089.txt AC 1755 ms 62828 KiB
test_0090.txt AC 1773 ms 63372 KiB
test_0091.txt AC 1766 ms 62964 KiB
test_0092.txt AC 1762 ms 62792 KiB
test_0093.txt AC 1760 ms 63240 KiB
test_0094.txt AC 1761 ms 63188 KiB
test_0095.txt AC 1757 ms 62744 KiB
test_0096.txt AC 1769 ms 63160 KiB
test_0097.txt AC 1759 ms 62744 KiB
test_0098.txt AC 1766 ms 63136 KiB
test_0099.txt AC 1766 ms 62616 KiB
test_0100.txt AC 1759 ms 63168 KiB
test_0101.txt AC 1756 ms 62960 KiB
test_0102.txt AC 1764 ms 62772 KiB
test_0103.txt AC 1762 ms 62972 KiB
test_0104.txt AC 1760 ms 62804 KiB
test_0105.txt AC 1764 ms 63092 KiB
test_0106.txt AC 1759 ms 63204 KiB
test_0107.txt AC 1756 ms 62544 KiB
test_0108.txt AC 1757 ms 62700 KiB
test_0109.txt AC 1763 ms 62788 KiB
test_0110.txt AC 1758 ms 63116 KiB
test_0111.txt AC 1761 ms 63256 KiB
test_0112.txt AC 1761 ms 63016 KiB
test_0113.txt AC 1758 ms 63228 KiB
test_0114.txt AC 1762 ms 63140 KiB
test_0115.txt AC 1769 ms 62920 KiB
test_0116.txt AC 1754 ms 63068 KiB
test_0117.txt AC 1764 ms 63180 KiB
test_0118.txt AC 1760 ms 63008 KiB
test_0119.txt AC 1757 ms 63372 KiB
test_0120.txt AC 1751 ms 63136 KiB
test_0121.txt AC 1761 ms 62924 KiB
test_0122.txt AC 1762 ms 63440 KiB
test_0123.txt AC 1769 ms 62904 KiB
test_0124.txt AC 1772 ms 63412 KiB
test_0125.txt AC 1773 ms 63424 KiB
test_0126.txt AC 1766 ms 62768 KiB
test_0127.txt AC 1757 ms 62840 KiB
test_0128.txt AC 1762 ms 63204 KiB
test_0129.txt AC 1758 ms 62816 KiB
test_0130.txt AC 1762 ms 63092 KiB
test_0131.txt AC 1761 ms 62664 KiB
test_0132.txt AC 1759 ms 63176 KiB
test_0133.txt AC 1766 ms 62500 KiB
test_0134.txt AC 1758 ms 63104 KiB
test_0135.txt AC 1761 ms 62688 KiB
test_0136.txt AC 1758 ms 62916 KiB
test_0137.txt AC 1760 ms 62988 KiB
test_0138.txt AC 1757 ms 62752 KiB
test_0139.txt AC 1750 ms 63304 KiB
test_0140.txt AC 1765 ms 62744 KiB
test_0141.txt AC 1767 ms 63220 KiB
test_0142.txt AC 1758 ms 63072 KiB
test_0143.txt AC 1760 ms 63136 KiB
test_0144.txt AC 1768 ms 62756 KiB
test_0145.txt AC 1763 ms 63704 KiB
test_0146.txt AC 1755 ms 63280 KiB
test_0147.txt AC 1753 ms 62784 KiB
test_0148.txt AC 1765 ms 63016 KiB
test_0149.txt AC 1757 ms 62744 KiB