結果

問題 No.5007 Steiner Space Travel
ユーザー Yu_212Yu_212
提出日時 2022-07-30 15:47:55
言語 Java21
(openjdk 21)
結果
AC  
実行時間 850 ms / 1,000 ms
コード長 17,756 bytes
コンパイル時間 2,765 ms
実行使用メモリ 89,448 KB
スコア 8,670,478
最終ジャッジ日時 2022-07-30 15:48:26
合計ジャッジ時間 30,144 ms
ジャッジサーバーID
(参考情報)
judge10 / judge15
純コード判定しない問題か言語
このコードへのチャレンジ
(要ログイン)

テストケース

テストケース表示
入力 結果 実行時間
実行使用メモリ
testcase_00 AC 834 ms
83,124 KB
testcase_01 AC 850 ms
83,268 KB
testcase_02 AC 829 ms
89,108 KB
testcase_03 AC 819 ms
83,920 KB
testcase_04 AC 826 ms
83,748 KB
testcase_05 AC 840 ms
89,012 KB
testcase_06 AC 812 ms
88,696 KB
testcase_07 AC 832 ms
82,836 KB
testcase_08 AC 831 ms
82,456 KB
testcase_09 AC 812 ms
84,768 KB
testcase_10 AC 834 ms
89,408 KB
testcase_11 AC 827 ms
89,140 KB
testcase_12 AC 815 ms
83,960 KB
testcase_13 AC 811 ms
84,072 KB
testcase_14 AC 836 ms
89,344 KB
testcase_15 AC 820 ms
86,172 KB
testcase_16 AC 834 ms
83,432 KB
testcase_17 AC 813 ms
82,736 KB
testcase_18 AC 831 ms
83,060 KB
testcase_19 AC 812 ms
82,856 KB
testcase_20 AC 826 ms
88,976 KB
testcase_21 AC 812 ms
82,120 KB
testcase_22 AC 810 ms
82,952 KB
testcase_23 AC 814 ms
84,424 KB
testcase_24 AC 813 ms
83,768 KB
testcase_25 AC 831 ms
89,424 KB
testcase_26 AC 838 ms
89,448 KB
testcase_27 AC 828 ms
88,716 KB
testcase_28 AC 830 ms
83,360 KB
testcase_29 AC 812 ms
83,724 KB
権限があれば一括ダウンロードができます

ソースコード

diff #

import java.io.*;
import java.util.*;
import java.util.concurrent.ThreadLocalRandom;
import java.util.function.IntUnaryOperator;
import java.util.function.LongUnaryOperator;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

public class Main {
    boolean isLocal;
    Random rand = new Random();
    In in = new In(System.in);
    PrintStream out = System.out;
    long inf = 0x1fffffffffffffffL;
    int iinf = 0x3fffffff;
    long startTime;

    private static final int s = 1001;
    private static final int n = 100;
    private static final int m = 8;
    Pos[] planets = new Pos[n];
    boolean[] grid = new boolean[s * s];
    int[][] dist = new int[n][n];
    int[][] neighbor = new int[n][n - 1];

    long solve(int seed) {
        startTime = System.currentTimeMillis();
        in();
        State state = initialState();
        while (!elapsed(500)) {
            state.optimize();
        }
        class St {
            private final Pos p;
            private final int upd;

            St(Pos p, int upd) {
                this.p = p;
                this.upd = upd;
            }
        }
        debug(state.ds);
        List<St> cand = new ArrayList<>();
        for (int i = 0; i < 500; i++) {
            Pos p = pos(rand.next(s), rand.next(s));
            int upd = state.station(0, p, false);
            debug(p, upd);
            cand.add(new St(p, upd));
        }
        cand.sort(Comparator.comparingInt(st -> st.upd));
        for (St st : cand) {
            int best = 0;
            int bi = -1;
            for (int i = 0; i < m; i++) {
                int upd = state.station(i, st.p, false);
                if (best > upd) {
                    best = upd;
                    bi = i;
                }
            }
            debug(bi, st.p, st.upd, best);
            if (bi != -1) {
                state.station(bi, st.p, true);
            }
        }
        debug(state.ds);
        answer(state);
        return isLocal ? Math.round(1000000000.0 / (Math.sqrt(state.ds) + 1000)) : 0;
    }

    void in() {
        Pos.init(1001, 1001);
        in.nextInt();
        in.nextInt();
        for (int i = 0; i < n; i++) {
            int a = in.nextInt();
            int b = in.nextInt();
            planets[i] = pos(a, b);
            grid[planets[i].z] = true;
        }
        IntStream.range(0, n).forEach(i -> {
            Integer[] a = new Integer[n - 1];
            Arrays.setAll(dist[i], j -> planets[i].dist(planets[j]) * 25);
            Arrays.setAll(a, j -> j < i ? j : j + 1);
            Arrays.sort(a, Comparator.comparingLong(j -> dist[i][j]));
            Arrays.setAll(neighbor[i], j -> a[j]);
        });
    }

    class State {
        double score;
        boolean hasScore;
        State prevCopy;
        int ds;
        int[] tour;
        int[] position;
        Pos[] station;
        int[] relay;

        State(int[] tour, int[] position, int ds, int[] relay, Pos[] station) {
            this.tour = tour;
            this.position = position;
            this.ds = ds;
            this.station = station;
            this.relay = relay;
        }

        State(State prev) {
            this.score = prev.score;
            this.hasScore = true;
        }

        State rollback() {
            return prevCopy;
        }

        int neighbor0(double stage) {
            return 0;
        }

        int neighbor(double stage) {
            hasScore = false;
            prevCopy = copy();
            return neighbor0(stage);
        }

        State copy() {
            return new State(this);
        }

        boolean tryTwoOpt() {
            boolean updated = false;
            for (int i = 0; i < n; i++) {
                int a = tour[i];
                int b = tour[i + 1 < n ? i + 1 : 0];
                for (int k = 0; k < n - 1; k++) {
                    int j = position[neighbor[a][k]];
                    int c = tour[j];
                    int d = tour[j + 1 < n ? j + 1 : 0];
                    if (a == d || b == c) {
                        continue;
                    }
                    if (dist[a][c] > dist[a][b]) {
                        break;
                    }
                    long before = dist[a][b] + dist[c][d];
                    long after = dist[a][c] + dist[b][d];
                    if (after < before) {
                        twoOpt(i, j);
                        updated = true;
                        break;
                    }
                }
            }
            return updated;
        }

        void twoOpt(int i, int j) {
            if (i > j) {
                int temp = i;
                i = j;
                j = temp;
            }
            while (i + 1 < j) {
                i++;
                int temp = tour[i];
                tour[i] = tour[j];
                tour[j] = temp;
                position[tour[i]] = i;
                position[tour[j]] = j;
                j--;
            }
        }

        void doubleBridge() {
            int[] i = new int[4];
            do {
                Arrays.setAll(i, j -> rand.next(n));
                Arrays.sort(i);
            } while (!(i[0] + 1 < i[1] && i[1] + 1 < i[2] && i[2] + 1 < i[3] && (0 < i[0] || i[3] < n - 1)));
            int a = i[1] - i[0];
            int b = i[2] - i[1];
            int c = i[3] - i[2];
            int[] copy = Arrays.copyOfRange(tour, i[0] + 1, i[3] + 1);
            int k = i[0] + 1;
            for (int j = 0; j < c; j++) {
                tour[k + j] = copy[a + b + j];
                position[copy[a + b + j]] = k + j;
            }
            k += c;
            for (int j = 0; j < b; j++) {
                tour[k + j] = copy[a + j];
                position[copy[a + j]] = k + j;
            }
            k += b;
            for (int j = 0; j < a; j++) {
                tour[k + j] = copy[j];
                position[copy[j]] = k + j;
            }
        }

        void optimize() {
            int[] oldTour = tour.clone();
            int[] oldPosition = position.clone();
            doubleBridge();
            while (tryTwoOpt());
            int nds = calcDist();
            if (ds > nds) {
                ds = nds;
            } else {
                tour = oldTour;
                position = oldPosition;
            }
        }

        int station(int k, Pos p, boolean change) {
            Pos old = station[k];
            station[k] = p;
            int ods = ds;
            int sum = 0;
            for (int i = 0; i < n; i++) {
                sum += optRelay(i, change);
            }
            if (change) {
                ds = sum;
            } else {
                station[k] = old;
            }
            return sum - ods;
        }

        int optRelay(int i, boolean change) {
            int j = i == n - 1 ? 0 : i + 1;
            if (change) relay[i] = -1;
            int min = dist[tour[i]][tour[j]];
            for (int k = 0; k < m; k++) {
                int upd = dist(tour[i], station[k], tour[j]);
                if (min > upd) {
                    min = upd;
                    if (change) relay[i] = k;
                }
            }
            return min;
        }

        int dist(int i, Pos r, int j) {
            if (r == null) {
                return dist[i][j];
            } else {
                return (planets[i].dist(r) + r.dist(planets[j])) * 5;
            }
        }

        int calcDist() {
            int ds = 0;
            for (int i = 0; i < n; i++) {
                int j = i == n - 1 ? 0 : i + 1;
                ds += dist[tour[i]][tour[j]];
            }
            return ds;
        }

        double getScore() {
            if (!hasScore) {
                score = calcScore();
                hasScore = true;
            }
            return score;
        }

        double calcScore() {
            double score = 0;
            return score;
        }

        long realScore() {
            int score = 0;
            return score;
        }
    }

    State initialState() {
        int[] tour = new int[n];
        int[] position = new int[n];
        BitSet used = new BitSet(n);
        used.set(0);
        int ds = 0;
        int prev = 0;
        for (int i = 1; i < n; i++) {
            for (int k = 0; k < n - 1; k++) {
                int j = neighbor[prev][k];
                if (!used.get(j)) {
                    ds += dist[prev][j];
                    prev = j;
                    tour[i] = j;
                    position[j] = i;
                    used.set(j);
                    break;
                }
            }
        }
        Pos[] station = new Pos[m];
        int[] relay = new int[n];
        Arrays.fill(relay, -1);
        return new State(tour, position, ds, relay, station);
    }

    void answer(State state) {
        for (Pos pos : state.station) {
            if (pos == null) {
                out.println("0 0");
            } else {
                out.println(pos.x + " " + pos.y);
            }
        }
        int k = n + 1;
        for (int i = 0; i < n; i++) {
            if (state.relay[i] != -1) {
                k++;
            }
        }
        out.println(k);
        for (int i = 0; i < n; i++) {
            out.println("1 " + (state.tour[i] + 1));
            if (state.relay[i] != -1) {
                out.println("2 " + (state.relay[i] + 1));
            }
        }
        out.println("1 1");
    }

    void debug(Object... args) {
        if (args == null || args.getClass() != Object[].class) {
            args = new Object[] {args};
        }
        System.err.println(Arrays.stream(args).map(obj -> {
            Class<?> clazz = obj == null ? null : obj.getClass();
            return clazz == byte[].class ? Arrays.toString((byte[])obj) :
                   clazz == short[].class ? Arrays.toString((short[])obj) :
                   clazz == int[].class ? Arrays.toString((int[])obj) :
                   clazz == long[].class ? Arrays.toString((long[])obj) :
                   clazz == char[].class ? Arrays.toString((char[])obj) :
                   clazz == float[].class ? Arrays.toString((float[])obj) :
                   clazz == double[].class ? Arrays.toString((double[])obj) :
                   clazz == boolean[].class ? Arrays.toString((boolean[])obj) :
                   obj instanceof Object[] ? Arrays.deepToString((Object[])obj) :
                   String.valueOf(obj);
        }).collect(Collectors.joining(" ")));
    }

    Pos pos(int x, int y) {
        return Pos.instances[y * s + x];
    }

    Pos pos(int z) {
        return Pos.instances[z];
    }

    static class Pos implements Comparable<Pos> {
        static Pos[] instances;
        static void init(int h, int w) {
            instances = new Pos[h * w];
            for (int i = 0; i < h * w; i++) {
                instances[i] = new Pos(i % w, i / w, i);
            }
        }

        final int x, y, z;

        private Pos(int x, int y, int z) {
            this.x = x;
            this.y = y;
            this.z = z;
        }

        int dist(Pos o) {
            int xd = (x - o.x);
            int yd = (y - o.y);
            return xd * xd + yd * yd;
        }

        @Override
        public int compareTo(Pos o) {
            return Integer.compare(z, o.z);
        }

        @Override
        public boolean equals(Object o) {
            return o instanceof Pos && z == ((Pos)o).z;
        }

        @Override
        public int hashCode() {
            return z;
        }

        @Override
        public String toString() {
            return String.format("(%d, %d)", x, y);
        }
    }

    State climbing(State state, long timeLimit) {
        timeLimit *= 1000000;
        long startTime = System.nanoTime();
        State bestState = state.copy();
        double bestScore = state.getScore();
        while (true) {
            long nowTime = System.nanoTime() - startTime;
            if (nowTime >= timeLimit) {
                break;
            }
            double prevScore = state.getScore();
            state.neighbor((double)nowTime / timeLimit);
            if (bestScore < state.getScore()) {
                bestScore = state.getScore();
                bestState = state.copy();
            }
            if (state.getScore() < prevScore) {
                state = state.rollback();
            }
        }
        return bestState;
    }

    State annealing(State state, double startTemp, double endTemp, long timeLimit) {
        State bestState = state.copy();
        double bestScore = state.getScore();
        while (true) {
            long nowTime = System.currentTimeMillis() - startTime;
            if (nowTime >= timeLimit) {
                break;
            }
            double prevScore = state.getScore();
            int nid = state.neighbor((double)nowTime / timeLimit);
            if (nid == -1) {
                continue;
            }
            if (bestScore < state.getScore()) {
                bestScore = state.getScore();
                bestState = state.copy();
            }
            double diff = state.getScore() - prevScore;
            double temp = startTemp + (endTemp - startTemp) * nowTime / timeLimit;
            double p = diff > 0 ? 1 : Math.exp(diff / temp);
            if (rand.nextDouble() >= p) {
                state = state.rollback();
            }
        }
        return bestState;
    }

    long elapsed() {
        return (long)((System.currentTimeMillis() - startTime) * (isLocal ? 1.7 : 1));
    }

    boolean elapsed(long timeLimit) {
        return elapsed() >= timeLimit;
    }

    public static void main(String[] args) {
        new Main().solve(0);
    }

    static class Random {
        private long x, y, z, w;

        Random() {
            this(ThreadLocalRandom.current().nextLong());
        }

        Random(long seed) {
            this.x = seed;
            for (int i = 0; i < 20; i++) {
                rand();
            }
        }

        private long rand() {
            long t = x ^ (x << 11);
            x = y;
            y = z;
            z = w;
            w = w ^ (w >>> 19) ^ t ^ (t >>> 8);
            return x & 0x7fffffff;
        }

        long next() {
            return rand() << 31 | rand();
        }

        int next(int n) {
            return (int)(rand() % n);
        }

        int next(int l, int r) {
            return (int)(rand() % (r - l) + l);
        }

        double nextDouble() {
            return rand() / 2147483647.0;
        }
    }

    static class In {
        private final BufferedReader reader;
        private StringTokenizer tokenizer;

        public In(InputStream input) {
            this.reader = new BufferedReader(new InputStreamReader(input), 0x10000);
        }

        String next() {
            try {
                while (tokenizer == null || !tokenizer.hasMoreTokens()) {
                    tokenizer = new StringTokenizer(reader.readLine());
                }
            } catch (IOException ignored) {
            }
            return tokenizer.nextToken();
        }

        int nextInt() {
            return Integer.parseInt(next());
        }

        long nextLong() {
            return Long.parseLong(next());
        }

        double nextDouble() {
            return Double.parseDouble(next());
        }

        char[] nextCharArray() {
            return next().toCharArray();
        }

        String[] nextStringArray(int n) {
            String[] s = new String[n];
            for (int i = 0; i < n; i++) {
                s[i] = next();
            }
            return s;
        }

        char[][] nextCharGrid(int n, int m) {
            char[][] a = new char[n][m];
            for (int i = 0; i < n; i++) {
                a[i] = next().toCharArray();
            }
            return a;
        }

        int[] nextIntArray(int n) {
            int[] a = new int[n];
            for (int i = 0; i < n; i++) {
                a[i] = nextInt();
            }
            return a;
        }

        int[] nextIntArray(int n, IntUnaryOperator op) {
            int[] a = new int[n];
            for (int i = 0; i < n; i++) {
                a[i] = op.applyAsInt(nextInt());
            }
            return a;
        }

        int[][] nextIntMatrix(int h, int w) {
            int[][] a = new int[h][w];
            for (int i = 0; i < h; i++) {
                a[i] = nextIntArray(w);
            }
            return a;
        }

        long[] nextLongArray(int n) {
            long[] a = new long[n];
            for (int i = 0; i < n; i++) {
                a[i] = nextLong();
            }
            return a;
        }

        long[] nextLongArray(int n, LongUnaryOperator op) {
            long[] a = new long[n];
            for (int i = 0; i < n; i++) {
                a[i] = op.applyAsLong(nextLong());
            }
            return a;
        }

        long[][] nextLongMatrix(int h, int w) {
            long[][] a = new long[h][w];
            for (int i = 0; i < h; i++) {
                a[i] = nextLongArray(w);
            }
            return a;
        }

        List<List<Integer>> nextEdges(int n, int m, boolean directed) {
            List<List<Integer>> res = new ArrayList<>();
            for (int i = 0; i < n; i++) {
                res.add(new ArrayList<>());
            }
            for (int i = 0; i < m; i++) {
                int u = nextInt() - 1;
                int v = nextInt() - 1;
                res.get(u).add(v);
                if (!directed) {
                    res.get(v).add(u);
                }
            }
            return res;
        }
    }
}
0