// File: estan[P]tsp/tsp.cpp
// Function: std::vector<unsigned short, std::allocator<unsigned short>> approximate<std::chrono::_V2::system_clock>(std::istream&, std::chrono::time_point<std::chrono::_V2::system_clock, std::chrono::_V2::system_clock::duration> const&)
vector<uint16_t> approximate(istream &in, const chrono::time_point<T>& deadline) {
    /*
     * Initialization.
     */

    // Deadline for 3-opt inside main loop is 50 ms before hard deadline.
    chrono::milliseconds fifty_ms(50);
    auto threeOptDeadline = deadline - fifty_ms;

    // Calculate distance / K-nearest neighbors matrix.
    const Matrix<uint32_t> d = createDistanceMatrix(in);
    const Matrix<uint16_t> neighbor = createNeighborsMatrix(d, MAX_K);
    const uint32_t min = minDistance(d); // Shortest distance.
    const size_t N = d.rows();           // Number of cities.

    // Generate initial greedy tour.
    vector<uint16_t> tour = greedy(d);

    // Create max / position for initial 2-opt + 3-opt.
    vector<uint16_t> position(N);
    uint32_t max = 0;
    for (uint16_t i = 0; i < N; ++i) {
        max = std::max(max, d[i][(i + 1) % N]); // Maximum distance in tour.
        position[tour[i]] = i;                  // tour[i] is i:th city in tour.
    }

    /*
     * Main loop.
     *
     * We repeatedly
     *
     *   1) Optimize the tour with 2-opt + 3-opt.
     *   2) "Kick" the tour with a random 4-exchange.
     *
     * until only max(50, 2 * average iteration time) milliseconds remains
     * before deadline, and then pick the shortest tour we found.
     */

    // Some main loop statistics.
    size_t i = 0;                        // Number of iterations of main loop.
    chrono::milliseconds totalTime(0);   // Total time spent in main loop.
    chrono::milliseconds averageTime(0); // Average main loop iteration time.

    vector<uint16_t> shortestTour = tour;          // Best tour found.
    uint64_t shortestTourLength = length(tour, d); // Length of best tour found.

    for (i = 0; (now() + std::max(fifty_ms, 2 * averageTime)) < deadline; ++i) {
        auto start = now();

        // Optimize tour with 2-opt + 3-opt.
        twoOpt(tour, d, neighbor, position, max, min);
        threeOpt(tour, d, neighbor, position, max, min, threeOptDeadline);

        uint64_t tourLength = length(tour, d);
        if (tourLength < shortestTourLength) {
            // Shorter tour found.
            shortestTour = tour;
            shortestTourLength = tourLength;
        }

        if (N >= 8) {
            // Perform random 4-opt "double bridge" move.
            tour = doubleBridge(tour);
        } else {
            // Tiny tour, so just shuffle it instead.
            shuffle(tour.begin(), tour.end(), rng);
        }

        // Update max / position needed by fast 2/3-opt.
        max = 0;
        for (uint16_t j = 0; j < N; ++j) {
            max = std::max(max, d[tour[j]][tour[(j + 1) % N]]);
            position[tour[j]] = j;
        }

        // Collect statistics.
        totalTime += chrono::duration_cast<chrono::milliseconds>(now() - start);
        averageTime = totalTime / (i + 1);
    }

    LOG("Main Loop Statistics");
    LOG("  iterations: " << i);
    LOG("  totalTime: " << totalTime);
    LOG("  averageTime: " << averageTime);

    return shortestTour;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x250, %rsp            # imm = 0x250
movq %rdi, -0x1a0(%rbp)
movq %rdi, %rax
movq %rax, -0x198(%rbp)
movq %rdi, -0x8(%rbp)
movq %rsi, -0x10(%rbp)
movq %rdx, -0x18(%rbp)
movq $0x32, -0x20(%rbp)
movq -0x18(%rbp), %rdi
leaq -0x20(%rbp), %rsi
callq 0x6230
movq %rax, -0x28(%rbp)
movq -0x10(%rbp), %rsi
leaq -0x50(%rbp), %rdi
movq %rdi, -0x190(%rbp)
callq 0x2470
movq -0x190(%rbp), %rsi
leaq -0x78(%rbp), %rdi
movl $0x14, %edx
callq 0x27f0
jmp 0x3d0c
leaq -0x50(%rbp), %rdi
callq 0x23c0
movl %eax, -0x1a4(%rbp)
jmp 0x3d1d
movl -0x1a4(%rbp), %eax
movl %eax, -0x88(%rbp)
leaq -0x50(%rbp), %rdi
movq %rdi, -0x1b0(%rbp)
callq 0x3630
movq -0x1b0(%rbp), %rsi
movq %rax, -0x90(%rbp)
leaq -0xa8(%rbp), %rdi
callq 0x6280
jmp 0x3d55
movq -0x90(%rbp), %rax
movq %rax, -0x1c0(%rbp)
leaq -0xc1(%rbp), %rdi
movq %rdi, -0x1b8(%rbp)
callq 0x3a20
movq -0x1c0(%rbp), %rsi
movq -0x1b8(%rbp), %rdx
leaq -0xc0(%rbp), %rdi
callq 0x3a40
jmp 0x3d92
leaq -0xc1(%rbp), %rdi
callq 0x3ab0
movl $0x0, -0xc8(%rbp)
movw $0x0, -0xca(%rbp)
movzwl -0xca(%rbp), %eax
cmpq -0x90(%rbp), %rax
jae 0x3ed5
movzwl -0xca(%rbp), %esi
leaq -0x50(%rbp), %rdi
callq 0x36a0
movq %rax, -0x1d0(%rbp)
movzwl -0xca(%rbp), %eax
incl %eax
movq -0x90(%rbp), %rcx
xorl %edx, %edx
divq %rcx
movq -0x1d0(%rbp), %rax
movl %edx, %ecx
movl %ecx, %ecx
leaq (%rax,%rcx,4), %rsi
leaq -0xc8(%rbp), %rdi
callq 0x6600
movq %rax, -0x1c8(%rbp)
jmp 0x3e15
movq -0x1c8(%rbp), %rax
movl (%rax), %eax
movl %eax, -0xc8(%rbp)
movw -0xca(%rbp), %ax
movw %ax, -0x1d2(%rbp)
movzwl -0xca(%rbp), %eax
movl %eax, %esi
leaq -0xa8(%rbp), %rdi
callq 0x3ad0
movzwl (%rax), %eax
movl %eax, %esi
leaq -0xc0(%rbp), %rdi
callq 0x3ad0
movw -0x1d2(%rbp), %cx
movw %cx, (%rax)
movw -0xca(%rbp), %ax
addw $0x1, %ax
movw %ax, -0xca(%rbp)
jmp 0x3db1
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x80(%rbp)
movl %eax, -0x84(%rbp)
jmp 0x43bf
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x80(%rbp)
movl %eax, -0x84(%rbp)
jmp 0x43b6
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x80(%rbp)
movl %eax, -0x84(%rbp)
leaq -0xc1(%rbp), %rdi
callq 0x3ab0
jmp 0x43aa
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x80(%rbp)
movl %eax, -0x84(%rbp)
jmp 0x439e
movq -0x1a0(%rbp), %rdi
movq $0x0, -0xd8(%rbp)
movq $0x0, -0xe0(%rbp)
movq $0x0, -0xe8(%rbp)
movb $0x0, -0xe9(%rbp)
leaq -0xa8(%rbp), %rsi
callq 0x6640
jmp 0x3f12
leaq -0xa8(%rbp), %rdi
leaq -0x50(%rbp), %rsi
callq 0x6730
movq %rax, -0x1e0(%rbp)
jmp 0x3f2b
movq -0x1e0(%rbp), %rax
movq %rax, -0xf8(%rbp)
movq $0x0, -0xd8(%rbp)
callq 0x2c60
movq %rax, -0x108(%rbp)
movl $0x2, -0x114(%rbp)
leaq -0x114(%rbp), %rdi
leaq -0xe8(%rbp), %rsi
callq 0x6870
movq %rax, -0x1e8(%rbp)
jmp 0x3f76
movq -0x1e8(%rbp), %rax
movq %rax, -0x110(%rbp)
leaq -0x20(%rbp), %rdi
leaq -0x110(%rbp), %rsi
callq 0x6830
movq %rax, -0x1f0(%rbp)
jmp 0x3f9d
movq -0x1f0(%rbp), %rsi
leaq -0x108(%rbp), %rdi
callq 0x43e0
movq %rax, -0x1f8(%rbp)
jmp 0x3fb9
movq -0x1f8(%rbp), %rax
movq %rax, -0x100(%rbp)
movq -0x18(%rbp), %rsi
leaq -0x100(%rbp), %rdi
callq 0x67f0
movb %al, -0x1f9(%rbp)
jmp 0x3fdf
movb -0x1f9(%rbp), %al
testb $0x1, %al
jne 0x3fee
jmp 0x4348
callq 0x2c60
movq %rax, -0x120(%rbp)
movl -0x88(%rbp), %r9d
leaq -0xa8(%rbp), %rdi
leaq -0x50(%rbp), %rsi
leaq -0x78(%rbp), %rdx
leaq -0xc0(%rbp), %rcx
leaq -0xc8(%rbp), %r8
callq 0x68a0
jmp 0x4025
movl -0x88(%rbp), %r9d
movq %rsp, %rax
leaq -0x28(%rbp), %rcx
movq %rcx, (%rax)
leaq -0xa8(%rbp), %rdi
leaq -0x50(%rbp), %rsi
leaq -0x78(%rbp), %rdx
leaq -0xc0(%rbp), %rcx
leaq -0xc8(%rbp), %r8
callq 0x6b80
jmp 0x405a
leaq -0xa8(%rbp), %rdi
leaq -0x50(%rbp), %rsi
callq 0x6730
movq %rax, -0x208(%rbp)
jmp 0x4073
movq -0x208(%rbp), %rax
movq %rax, -0x128(%rbp)
movq -0x128(%rbp), %rax
cmpq -0xf8(%rbp), %rax
jae 0x40d6
movq -0x1a0(%rbp), %rdi
leaq -0xa8(%rbp), %rsi
callq 0x7780
jmp 0x40a6
movq -0x128(%rbp), %rax
movq %rax, -0xf8(%rbp)
jmp 0x40d6
movq -0x1a0(%rbp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x80(%rbp)
movl %eax, -0x84(%rbp)
callq 0x3c20
jmp 0x439e
cmpq $0x8, -0x90(%rbp)
jb 0x4116
leaq -0x140(%rbp), %rdi
leaq -0xa8(%rbp), %rsi
callq 0x79c0
jmp 0x40f5
leaq -0xa8(%rbp), %rdi
leaq -0x140(%rbp), %rsi
callq 0x7d50
leaq -0x140(%rbp), %rdi
callq 0x3c20
jmp 0x4161
leaq -0xa8(%rbp), %rdi
movq %rdi, -0x210(%rbp)
callq 0x3af0
movq -0x210(%rbp), %rdi
movq %rax, -0x148(%rbp)
callq 0x3b60
movq %rax, -0x150(%rbp)
movq -0x148(%rbp), %rdi
movq -0x150(%rbp), %rsi
leaq 0xe360(%rip), %rdx      # 0x124b8
callq 0x7d80
jmp 0x415f
jmp 0x4161
movl $0x0, -0xc8(%rbp)
movw $0x0, -0x152(%rbp)
movzwl -0x152(%rbp), %eax
cmpq -0x90(%rbp), %rax
jae 0x4265
movzwl -0x152(%rbp), %eax
movl %eax, %esi
leaq -0xa8(%rbp), %rdi
movq %rdi, -0x228(%rbp)
callq 0x3ad0
movzwl (%rax), %esi
leaq -0x50(%rbp), %rdi
callq 0x36a0
movq -0x228(%rbp), %rdi
movq %rax, -0x220(%rbp)
movzwl -0x152(%rbp), %eax
incl %eax
movq -0x90(%rbp), %rcx
xorl %edx, %edx
divq %rcx
movq %rdx, %rsi
callq 0x3ad0
movq %rax, %rcx
movq -0x220(%rbp), %rax
movzwl (%rcx), %ecx
leaq (%rax,%rcx,4), %rsi
leaq -0xc8(%rbp), %rdi
callq 0x6600
movq %rax, -0x218(%rbp)
jmp 0x4201
movq -0x218(%rbp), %rax
movl (%rax), %eax
movl %eax, -0xc8(%rbp)
movw -0x152(%rbp), %ax
movw %ax, -0x22a(%rbp)
movzwl -0x152(%rbp), %eax
movl %eax, %esi
leaq -0xa8(%rbp), %rdi
callq 0x3ad0
movzwl (%rax), %eax
movl %eax, %esi
leaq -0xc0(%rbp), %rdi
callq 0x3ad0
movw -0x22a(%rbp), %cx
movw %cx, (%rax)
movw -0x152(%rbp), %ax
addw $0x1, %ax
movw %ax, -0x152(%rbp)
jmp 0x4174
callq 0x2c60
movq %rax, -0x170(%rbp)
leaq -0x170(%rbp), %rdi
leaq -0x120(%rbp), %rsi
callq 0x8020
movq %rax, -0x238(%rbp)
jmp 0x428d
movq -0x238(%rbp), %rax
movq %rax, -0x168(%rbp)
leaq -0x168(%rbp), %rdi
callq 0x7ff0
movq %rax, -0x240(%rbp)
jmp 0x42b0
movq -0x240(%rbp), %rax
movq %rax, -0x160(%rbp)
leaq -0xe0(%rbp), %rdi
leaq -0x160(%rbp), %rsi
callq 0x8070
jmp 0x42d3
movq -0xd8(%rbp), %rax
incq %rax
movq %rax, -0x188(%rbp)
leaq -0xe0(%rbp), %rdi
leaq -0x188(%rbp), %rsi
callq 0x80b0
movq %rax, -0x248(%rbp)
jmp 0x4300
movq -0x248(%rbp), %rax
movq %rax, -0x180(%rbp)
leaq -0x178(%rbp), %rdi
leaq -0x180(%rbp), %rsi
callq 0x8100
jmp 0x4323
movq -0x178(%rbp), %rax
movq %rax, -0xe8(%rbp)
movq -0xd8(%rbp), %rax
addq $0x1, %rax
movq %rax, -0xd8(%rbp)
jmp 0x3f44
movb $0x1, -0xe9(%rbp)
testb $0x1, -0xe9(%rbp)
jne 0x4364
movq -0x1a0(%rbp), %rdi
callq 0x3c20
leaq -0xc0(%rbp), %rdi
callq 0x3c20
leaq -0xa8(%rbp), %rdi
callq 0x3c20
leaq -0x78(%rbp), %rdi
callq 0x3c80
leaq -0x50(%rbp), %rdi
callq 0x38a0
movq -0x198(%rbp), %rax
addq $0x250, %rsp            # imm = 0x250
popq %rbp
retq
leaq -0xc0(%rbp), %rdi
callq 0x3c20
leaq -0xa8(%rbp), %rdi
callq 0x3c20
leaq -0x78(%rbp), %rdi
callq 0x3c80
leaq -0x50(%rbp), %rdi
callq 0x38a0
movq -0x80(%rbp), %rdi
callq 0x21f0
nopw %cs:(%rax,%rax)
nopl (%rax,%rax)