Submission #39204745


Source Code Expand

import std;

enum Response {
    bedrock = 0,
    broken = 1,
    finish = 2,
    invalid = -1
}

struct Coordinate {
    int x, y;

    int calculateDistance(Coordinate that) {
        return abs(this.x-that.x) + abs(this.y-that.y);
    }
}

int N, W, K, C;
Coordinate[] sources, houses;

enum int P = 100;
enum int TIME_LIMIT = 4500;

struct State {
    ulong size;
    Coordinate[] coordinates;
    Coordinate[] starts, goals;
    int[] arr;
}

State resultState;

int[] sourceNumbers;
void preprocess() {
    sourceNumbers = new int[](K);

    auto distances = new int[](K);
    distances[] = int.max;
    foreach (i; 0 .. K) {
        foreach (j; 0 .. W) {
            int distance = houses[i].calculateDistance(sources[j]);
            if (distances[i] > distance) {
                distances[i] = distance;
                sourceNumbers[i] = j;
            }
        }
    }
}

const int[4] dx = [-1, 0, 1, 0], dy = [0, 1, 0, -1];

struct Field {
    State state;
    int[] arr;
    bool[][] isBroken, isSource;

    this(int[] a) {
        this.arr = a;

        this.isBroken = new bool[][](N, N);

        this.isSource = new bool[][](N, N);
        foreach (i; 0 .. W) {
            this.isSource[sources[i].x][sources[i].y] = true;
        }

        calculate();
    }

    Coordinate breadthFirstSearch(Coordinate start) {
        auto distances = new int[][](N, N);
        foreach (j; 0 .. N) distances[j][] = int.max;

        Coordinate[] queue;
        queue ~= start;
        distances[start.x][start.y] = 1;
        while (!queue.empty) {
            auto f = queue.front;
            queue.popFront;

            if (this.isSource[f.x][f.y]) {
                return f;
            }

            foreach (i; 0 .. 4) {
                int nx = f.x + dx[i], ny = f.y + dy[i];
                if (nx < 0 || N <= nx || ny < 0 || N <= ny) continue;
                if (distances[nx][ny] <= distances[f.x][f.y] + 1) continue;

                distances[nx][ny] = distances[f.x][f.y] + 1;
                queue ~= Coordinate(nx, ny);
            }
        }

        return Coordinate(-1, -1);
    }

    bool isMoveX(Coordinate start, Coordinate goal) {
        int countX;
        foreach (i; min(start.x, goal.x) .. max(start.x, goal.x)) {
            if (!this.isBroken[i][start.y]) ++countX;
        }
        foreach (i; min(start.y, goal.y) .. max(start.y, goal.y)+1) {
            if (!this.isBroken[goal.x][i]) ++countX;
        }

        int countY;
        foreach (i; min(start.y, goal.y) .. max(start.y, goal.y)) {
            if (!this.isBroken[start.x][i]) ++countY;
        }
        foreach (i; min(start.x, goal.x) .. max(start.x, goal.x)+1) {
            if (!this.isBroken[i][goal.y]) ++countY;
        }

        return countX <= countY;
    }

    void move(Coordinate start, Coordinate goal, bool isX) {
        int sx = start.x, sy = start.y;
        int gx = goal.x, gy = goal.y;

        if (isX) {
            if (sx <= gx) {
                foreach (i; sx .. gx) {
                    if (this.isBroken[i][sy]) return;

                    this.state.coordinates ~= Coordinate(i, sy);
                    this.isBroken[i][sy] = true;
                    this.isSource[i][sy] = true;
                }
            }
            else {
                for (int i = sx; i > gx; --i) {
                    if (this.isBroken[i][sy]) return;

                    this.state.coordinates ~= Coordinate(i, sy);
                    this.isBroken[i][sy] = true;
                    this.isSource[i][sy] = true;
                }
            }

            if (sy <= gy) {
                foreach (i; sy .. gy+1) {
                    if (this.isBroken[gx][i]) return;

                    this.state.coordinates ~= Coordinate(gx, i);
                    this.isBroken[gx][i] = true;
                    this.isSource[gx][i] = true;
                }
            }
            else {
                for (int i = sy; i >= gy; --i) {
                    if (this.isBroken[gx][i]) return;

                    this.state.coordinates ~= Coordinate(gx, i);
                    this.isBroken[gx][i] = true;
                    this.isSource[gx][i] = true;
                }
            }
        }
        else {
            if (sy <= gy) {
                foreach (i; sy .. gy) {
                    if (this.isBroken[sx][i]) return;

                    this.state.coordinates ~= Coordinate(sx, i);
                    this.isBroken[sx][i] = true;
                    this.isSource[sx][i] = true;
                }
            }
            else {
                for (int i = sy; i > gy; --i) {
                    if (this.isBroken[sx][i]) return;

                    this.state.coordinates ~= Coordinate(sx, i);
                    this.isBroken[sx][i] = true;
                    this.isSource[sx][i] = true;
                }
            }

            if (sx <= gx) {
                foreach (i; sx .. gx+1) {
                    if (this.isBroken[i][gy]) return;

                    this.state.coordinates ~= Coordinate(i, gy);
                    this.isBroken[i][gy] = true;
                    this.isSource[i][gy] = true;
                }
            }
            else {
                for (int i = sx; i >= gx; --i) {
                    if (this.isBroken[i][gy]) return;

                    this.state.coordinates ~= Coordinate(i, gy);
                    this.isBroken[i][gy] = true;
                    this.isSource[i][gy] = true;
                }
            }
        }
    }

    void calculate() {
        foreach (i, a; this.arr) {
            Coordinate goal = sources[sourceNumbers[a]];
            if (i > 0) {
                goal = breadthFirstSearch(houses[a]);
            }
            state.starts ~= houses[a];
            state.goals ~= goal;

            bool isX = isMoveX(houses[a], goal);
            move(houses[a], goal, isX);
        }

        state.size = state.coordinates.length;
        state.arr = arr;
    }
}

void solve() {
    SysTime startTime = Clock.currTime;

    resultState.size = ulong.max;

    preprocess();

    auto rnd = MinstdRand0(42);

    auto numbers = iota(K).array;
    while ((Clock.currTime - startTime).total!"msecs" < dur!"msecs"(TIME_LIMIT).total!"msecs") {
        auto arr = numbers.dup.randomShuffle(rnd).array;

        auto field = new Field(arr);

        if (resultState.size > field.state.size) {
            resultState = field.state;
        }
    }


    foreach (coordinate; resultState.coordinates) {
        Response response = Response.bedrock;
        while (response == Response.bedrock) {
            writefln("%d %d %d", coordinate.x, coordinate.y, P);
            stdout.flush;

            int input;
            readf("%d\n", input);

            if (input == 1) {
                response = Response.broken;
            }
            else if (input == 2) {
                response = Response.finish;
            }
            else if (input == -1) {
                response = Response.invalid;
            }
        }

        if (response == Response.finish || response == Response.invalid) {
            return;
        }
    }
}

void main() {
    readf("%d %d %d %d\n", N, W, K, C);

    sources.length = W;
    foreach (i; 0 .. W) readf("%d %d\n", sources[i].x, sources[i].y);

    houses.length = K;
    foreach (i; 0 .. K) readf("%d %d\n", houses[i].x, houses[i].y);

    solve();
}

Submission Info

Submission Time
Task A - Excavation
User kokatsu
Language D (LDC 1.20.1)
Score 13961073
Code Size 7700 Byte
Status AC
Exec Time 4553 ms
Memory 11460 KiB

Judge Result

Set Name test_ALL
Score / Max Score 13961073 / 50000000000
Status
AC × 50
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
Case Name Status Exec Time Memory
test_0000.txt AC 4525 ms 4024 KiB
test_0001.txt AC 4530 ms 4116 KiB
test_0002.txt AC 4553 ms 4132 KiB
test_0003.txt AC 4544 ms 4068 KiB
test_0004.txt AC 4540 ms 11460 KiB
test_0005.txt AC 4542 ms 4144 KiB
test_0006.txt AC 4531 ms 4092 KiB
test_0007.txt AC 4521 ms 4036 KiB
test_0008.txt AC 4535 ms 4172 KiB
test_0009.txt AC 4531 ms 4052 KiB
test_0010.txt AC 4538 ms 4080 KiB
test_0011.txt AC 4529 ms 4168 KiB
test_0012.txt AC 4539 ms 4096 KiB
test_0013.txt AC 4540 ms 4132 KiB
test_0014.txt AC 4524 ms 4100 KiB
test_0015.txt AC 4533 ms 4156 KiB
test_0016.txt AC 4535 ms 4068 KiB
test_0017.txt AC 4530 ms 4232 KiB
test_0018.txt AC 4541 ms 4068 KiB
test_0019.txt AC 4530 ms 4248 KiB
test_0020.txt AC 4536 ms 4072 KiB
test_0021.txt AC 4539 ms 4236 KiB
test_0022.txt AC 4549 ms 4184 KiB
test_0023.txt AC 4528 ms 4244 KiB
test_0024.txt AC 4527 ms 4040 KiB
test_0025.txt AC 4536 ms 4060 KiB
test_0026.txt AC 4547 ms 4136 KiB
test_0027.txt AC 4529 ms 4220 KiB
test_0028.txt AC 4526 ms 4140 KiB
test_0029.txt AC 4529 ms 4160 KiB
test_0030.txt AC 4537 ms 4156 KiB
test_0031.txt AC 4525 ms 4220 KiB
test_0032.txt AC 4544 ms 4124 KiB
test_0033.txt AC 4531 ms 4032 KiB
test_0034.txt AC 4531 ms 4116 KiB
test_0035.txt AC 4539 ms 4164 KiB
test_0036.txt AC 4533 ms 4128 KiB
test_0037.txt AC 4552 ms 4044 KiB
test_0038.txt AC 4523 ms 3996 KiB
test_0039.txt AC 4541 ms 4292 KiB
test_0040.txt AC 4535 ms 4036 KiB
test_0041.txt AC 4541 ms 4152 KiB
test_0042.txt AC 4539 ms 4276 KiB
test_0043.txt AC 4536 ms 4064 KiB
test_0044.txt AC 4527 ms 4212 KiB
test_0045.txt AC 4533 ms 4112 KiB
test_0046.txt AC 4529 ms 4220 KiB
test_0047.txt AC 4531 ms 4232 KiB
test_0048.txt AC 4534 ms 4148 KiB
test_0049.txt AC 4527 ms 4192 KiB