Nhân viên bán khoai tây nóng


23

Đưa ra một danh sách các điểm, tìm con đường ngắn nhất truy cập tất cả các điểm và trở về điểm bắt đầu.

Các Salesman Du lịch Vấn đề là nổi tiếng trong lĩnh vực khoa học máy tính, như rất nhiều cách để tính toán / xấp xỉ nó. Nó đã được giải quyết cho các nhóm điểm rất lớn, nhưng một số điểm lớn nhất phải mất nhiều năm để hoàn thành CPU.

Đừng để bị cháy bởi khoai tây.

Hot Potato là một trò chơi trong đó hơn 2 người chơi vượt qua một "củ khoai tây" trong một vòng tròn trong khi nhạc phát. Đối tượng là nhanh chóng chuyển nó cho người chơi tiếp theo. Nếu bạn đang cầm củ khoai tây khi nhạc dừng lại, bạn sẽ ra ngoài.


Đối tượng của nhân viên bán hàng khoai tây nóng là:

Cho một bộ 100 điểm duy nhất , trả lại các điểm đó theo thứ tự tốt hơn ( tổng khoảng cách ngắn hơn như được xác định tiếp theo ). Điều này sẽ "vượt qua" vấn đề cho người chơi tiếp theo. Họ phải cải thiện nó và chuyển nó sang người tiếp theo, v.v ... Nếu một người chơi không thể cải thiện nó, họ sẽ ra ngoài và tiếp tục chơi cho đến khi một người chơi còn lại.

Để giữ cho điều này không phải là một cuộc thi "brute-force-me-a-path", có những quy định sau:

  • Bạn không thể mất hơn một phút để vượt qua khoai tây. Nếu bạn chưa tìm thấy và thông qua một giải pháp ngắn hơn trước khi hết một phút, bạn sẽ ra ngoài.

  • Bạn không thể thay đổi vị trí của hơn 25 điểm. Để chính xác, >= 75điểm phải ở cùng vị trí với bạn đã nhận được chúng. Nó không quan trọng những người bạn quyết định thay đổi, chỉ là số lượng bạn thay đổi.

Khi chỉ còn một người chơi, anh ta là người chiến thắng trong trò chơi đó và nhận được một điểm. Một tourney bao gồm các 5*ntrò chơi, trong đó nsố lượng người chơi. Mỗi trò chơi, người chơi bắt đầu sẽ được xoay và thứ tự người chơi còn lại sẽ được xáo trộn . Người chơi có nhiều điểm nhất ở cuối là người chiến thắng giải đấu. Nếu tourney kết thúc với một chiếc cà vạt cho vị trí đầu tiên, một tourney mới sẽ chỉ được chơi với những thí sinh đó. Điều này sẽ tiếp tục cho đến khi không có sự ràng buộc.

Người chơi bắt đầu cho mỗi trò chơi sẽ nhận được một tập hợp các điểm được chọn giả ngẫu nhiên không theo thứ tự cụ thể.

Các điểm được định nghĩa là một cặp x,ytọa độ nguyên trên lưới cartesian. Khoảng cách được đo bằng khoảng cách Manhattan , |x1-x2| + |y1-y2|. Tất cả các tọa độ sẽ nằm trong [0..199]phạm vi.

Đầu vào

Đầu vào được đưa ra với một đối số chuỗi đơn. Nó sẽ bao gồm 201 số nguyên được phân tách bằng dấu phẩy đại diện cho số lượng người chơi hiện tại ( m) và 100 điểm:

m,x0,y0,x1,y1,x2,y2,...,x99,y99

Thứ tự của các điểm này là đường dẫn hiện tại. Tổng khoảng cách có được bằng cách thêm khoảng cách từ mỗi điểm đến điểm tiếp theo ( dist(0,1) + dist(1,2) + ... + dist(99,0)). Đừng quên quay lại để bắt đầu khi tính tổng khoảng cách!

Lưu ý rằng mkhông số lượng người chơi mà bắt đầu trò chơi, đó là con số đó vẫn đang ở.

Đầu ra

Đầu ra được đưa ra theo cách tương tự như đầu vào, trừ m; một chuỗi chứa các số nguyên được phân tách bằng dấu phẩy biểu thị các điểm theo thứ tự mới.

x0,y0,x1,y1,x2,y2,...,x99,y99

Chương trình điều khiển sẽ đợi đầu ra chỉ trong một phút. Khi đầu ra được nhận, nó sẽ xác minh rằng:

  • đầu ra được hình thành tốt
  • đầu ra bao gồm chỉtất cả 100 điểm trình bày trong đầu vào
  • >=75 điểm ở vị trí ban đầu của họ
  • độ dài đường dẫn nhỏ hơn đường dẫn trước

Nếu bất kỳ kiểm tra nào trong số này không thành công (hoặc không có đầu ra), bạn sẽ ra ngoài và trò chơi sẽ chuyển sang người chơi tiếp theo.

Chương trình điều khiển

Bạn có thể tìm thấy chương trình điều khiển tại liên kết này . Chương trình điều khiển chính nó là xác định, và được đăng với một hạt giống giả 1. Hạt giống được sử dụng trong quá trình ghi điểm sẽ khác nhau, vì vậy đừng cố gắng phân tích thứ tự lần lượt / danh sách điểm mà nó phun ra.

Các lớp chính là Tourney. Chạy này sẽ làm một giải đấu đầy đủ với các thí sinh được đưa ra như là đối số. Nó phun ra người chiến thắng của mỗi trò chơi và một kiểm đếm vào cuối. Một tourney mẫu có hai SwapBots trông giống như:

Starting tournament with seed 1

(0) SwapBot wins a game! Current score: 1
(1) SwapBot wins a game! Current score: 1
(1) SwapBot wins a game! Current score: 2
(1) SwapBot wins a game! Current score: 3
(0) SwapBot wins a game! Current score: 2
(1) SwapBot wins a game! Current score: 4
(1) SwapBot wins a game! Current score: 5
(1) SwapBot wins a game! Current score: 6
(1) SwapBot wins a game! Current score: 7
(1) SwapBot wins a game! Current score: 8

Final Results:

Wins        Contestant
2       (0) SwapBot
8       (1) SwapBot

Nếu bạn muốn kiểm tra chỉ một trò chơi cùng một lúc, bạn có thể chạy Gamelớp thay thế. Điều này sẽ chạy một trò chơi với người chơi theo thứ tự được đưa ra làm đối số. Theo mặc định, nó cũng sẽ in một lần phát cho thấy trình phát và độ dài đường dẫn hiện tại.

Cũng bao gồm một vài người chơi thử nghiệm: SwapBot, BlockPermuter, và TwoSwapBot. Hai cái đầu tiên sẽ không được bao gồm trong các lần chạy điểm, vì vậy hãy thoải mái sử dụng và lạm dụng chúng trong quá trình thử nghiệm. TwoSwapBot sẽ được đưa vào đánh giá, và anh ấy không hề lép vế, vì vậy hãy mang trò chơi A của bạn.

Sai

  • Bạn không thể lưu thông tin trạng thái và mỗi lượt là một lần chạy chương trình riêng biệt. Thông tin duy nhất bạn sẽ nhận được mỗi lượt là tập hợp các điểm.

  • Bạn không thể sử dụng tài nguyên bên ngoài. Điều này bao gồm các cuộc gọi mạng và truy cập tập tin.

  • Bạn không thể sử dụng các chức năng thư viện được thiết kế để giải quyết / hỗ trợ cho vấn đề TSP hoặc các biến thể của nó.

  • Bạn không thể thao túng hoặc can thiệp vào người chơi khác bằng mọi cách.

  • Bạn không thể thao tác hoặc can thiệp vào chương trình điều khiển hoặc bất kỳ lớp hoặc tệp được bao gồm trong bất kỳ cách nào.

  • Đa luồng được cho phép.

  • Một lần gửi cho mỗi người dùng. Nếu bạn gửi nhiều mục, tôi sẽ chỉ nhập mục đầu tiên được gửi. Nếu bạn muốn thay đổi trình của mình, hãy chỉnh sửa / xóa bản gốc.

  • Giải đấu sẽ được chạy trên Ubuntu 13.04, trên máy tính có CPU i7-3770K và RAM 16 GB. Nó sẽ không được chạy trong VM. Bất cứ điều gì tôi cho là độc hại sẽ ngay lập tức loại bỏ mục hiện tại bất kỳ mục nào trong tương lai bạn gửi.

  • Tất cả các mục phải được chạy từ dòng lệnh với phần mềm miễn phí ( như trong bia ). Nếu tôi gặp vấn đề trong việc biên dịch / chạy mục nhập của bạn, tôi sẽ yêu cầu trợ giúp trong các bình luận. Nếu bạn không trả lời hoặc cuối cùng tôi không thể chạy nó, nó sẽ bị loại.

Kết quả (ngày 22 tháng 5 năm 2014)

Kết quả mới là trong! UntangleBot đã đánh bại các đối thủ cạnh tranh khá tốt. TwoSwapBot đã quản lý bảy chiến thắng và SANNbot cũng giành được một chiến thắng. Đây là bảng điểm và liên kết đến đầu ra thô :

Wins        Contestant
22      (2) ./UntangleBot
7       (0) TwoSwapBot
1       (5) SANNbot.R
0       (1) BozoBot
0       (3) Threader
0       (4) DivideAndConquer

Khi đứng tại , UntangleBot đã giành được dấu kiểm. Tuy nhiên, đừng để điều đó ngăn cản bạn tham gia, vì tôi sẽ điều hành giải đấu khi có nhiều thí sinh xuất hiện và thay đổi câu trả lời được chấp nhận cho phù hợp.


Bình luận thanh trừng. Xin vui lòng thông báo cho tôi cho bất kỳ thông tin bị mất có thể.
Doorknob

Man tại sao thử thách này phải có trong kỳ thi cuối cùng của tôi (cuối cùng, được thực hiện với trường học yeay). Bạn chắc chắn là một Geobits lập kế hoạch tồi;) Thật kỳ lạ / đáng buồn vào thời điểm đó có hàng tấn câu hỏi của vua và bây giờ không có câu hỏi nào (có thể nó hoạt động tốt hơn nếu chỉ có một câu hỏi một lúc, gợi ý gợi ý) ...
Herjan

@Herjan Hãy thoải mái thử giải vô địch hiện tại. Tôi sẽ điều hành tourney một lần nữa khi các thí sinh mới xuất hiện, vì vậy cuộc thi sẽ không kết thúc hay gì cả. Đánh bại SirDarius và nó có thể thúc đẩy anh ta hoặc người khác đánh bại bạn, hít thở cuộc sống trở lại;)
Geobits

@Herjan Vui lòng gửi một mục! Tôi tin rằng có rất nhiều chỗ để cải thiện ở đây. Hầu hết các giải pháp ở đây, bao gồm cả của tôi, không dựa trên các thuật toán thông minh cụ thể cho vấn đề này.
SirDarius

Tôi nghĩ rằng có một vấn đề với giới hạn sửa đổi. Vì đôi khi sẽ phải sửa đổi toàn bộ tập hợp dữ liệu để có giải pháp tốt hơn.
Ilya Gazman

Câu trả lời:


8

UntangleBot (trước đây là NiceBot)

Một bot C ++ 11 sử dụng hai chiến lược.
Đầu tiên, nó sẽ cố gắng "gỡ rối" đường dẫn nếu có thể, bằng cách phát hiện các giao điểm giữa các đường dẫn gần hơn 25 điểm (vì việc gỡ rối ngụ ý sửa đổi tất cả các điểm ở giữa).
Nếu chiến lược đầu tiên thất bại, nó ngẫu nhiên hoán đổi các điểm để tìm khoảng cách tốt hơn cho đến khi tìm thấy đường dẫn tốt hơn.

Bot này liên tục đánh bại TwoSwapBot với tỷ lệ xấp xỉ năm chiến thắng cho một trận thua trong các giải đấu thử nghiệm của tôi.

// g++ -std=c++11 -O3 -o UntangleBot UntangleBot.cpp
#include <algorithm>
#include <chrono>
#include <cmath>
#include <iostream>
#include <iterator>
#include <random>
#include <set>
#include <sstream>

const int NPOINTS = 100;

struct Point {
    int x, y;

    Point():x(0),y(0) {}    
    Point(int x, int y):x(x),y(y) {}

    int distance_to(const Point & pt) const {
        return std::abs(x - pt.x) + std::abs(y - pt.y);
    }
};

std::ostream & operator<<(std::ostream & out, const Point & point) {
    return out << point.x << ',' << point.y;
}

int total_distance(const Point points[NPOINTS]) {
    int distance = 0;
    for (int i = 0; i < NPOINTS; ++i) {
        distance += points[i].distance_to(points[(i+1)%NPOINTS]);
    }
    return distance;
}

bool intersects(const Point & p1, const Point & p2, const Point & p3, const Point & p4) {
    double s1_x, s1_y, s2_x, s2_y;
    s1_x = p2.x - p1.x;
    s1_y = p2.y - p1.y;
    s2_x = p4.x - p3.x;
    s2_y = p4.y - p3.y;

    double s, t;
    s = (-s1_y * (p1.x - p3.x) + s1_x * (p1.y - p3.y)) / (-s2_x * s1_y + s1_x * s2_y);
    t = ( s2_x * (p1.y - p3.y) - s2_y * (p1.x - p3.x)) / (-s2_x * s1_y + s1_x * s2_y);

    return s >= 0 && s <= 1 && t >= 0 && t <= 1;
}

int main(int argc, char ** argv) {
    Point points[NPOINTS];

    using Clock = std::chrono::system_clock;
    const Clock::time_point start_time = Clock::now();

    // initialize points
    if (argc < 2) {
        std::cerr << "Point list is missing" << std::endl;
        return 1;
    }
    std::stringstream in(argv[1]);
    int players;
    char v;
    in >> players >> v;
    for (int i = 0; i < NPOINTS; ++i) {
        in >> points[i].x >> v >> points[i].y >> v;
    }

    int original_distance = total_distance(points);

    // detect intersection between any 4 points
    for (int i = 0; i < NPOINTS; ++i) {
        for (int j = i+1; j < NPOINTS; ++j) {
            Point & p1 = points[i];
            Point & p2 = points[(i+1)%NPOINTS];
            Point & p3 = points[j];
            Point & p4 = points[(j+1)%NPOINTS];

            // points must all be distinct
            if (p1.distance_to(p3) == 0 || p1.distance_to(p4) == 0 || p2.distance_to(p3) == 0 || p2.distance_to(p4) == 0) {
                continue;
            }

            // do they intersect ?
            if (!intersects(p1, p2, p3, p4)) {
                continue;
            }

            // can modify less than 25 points ?
            if (std::abs(j-i) > 25) {
                continue;
            }

            // swap points
            for (int m = 0; m < std::abs(j-i)/2; ++m) {
                if (i+1+m != j-m) {
                    std::swap(points[i+1+m], points[j-m]);
                    //std::cerr << "untangle " << i+1+m << " <=> " << j-m << '\n';
                }
            }

            int new_distance = total_distance(points);
            if (new_distance < original_distance) {
                std::copy(std::begin(points), std::end(points)-1, std::ostream_iterator<Point>(std::cout, ","));
                std::cout << points[NPOINTS-1];
                return 0;
            }
            else {
                // swap points back
                for (int m = 0; m < std::abs(j-i)/2; m++) {
                    if (i+1+m != j-m) {
                        std::swap(points[i+1+m], points[j-m]);
                    }
                }
            }
        }
    }

    // more traditional approach if the first fails
    std::mt19937 rng(std::chrono::duration_cast<std::chrono::seconds>(start_time.time_since_epoch()).count());
    std::uniform_int_distribution<> distr(0, NPOINTS-1);
    while (true) {
        // try all possible swaps from a random permutation
        int p1 = distr(rng);
        int p2 = distr(rng);
        std::swap(points[p1], points[p2]);

        for (int i = 0; i < NPOINTS; ++i) {
            for (int j = i+1; j < NPOINTS; ++j) {
                std::swap(points[i], points[j]);
                if (total_distance(points) < original_distance) {
                    std::copy(std::begin(points), std::end(points)-1, std::ostream_iterator<Point>(std::cout, ","));
                    std::cout << points[NPOINTS-1];
                    return 0;
                }
                else {
                    std::swap(points[i], points[j]);
                }
            }
        }

        // they didn't yield a shorter path, swap the points back and try again
        std::swap(points[p1], points[p2]);
    }
    return 0;
}

Bạn đánh tôi 19 phút!
Rainbolt

Điều này nên có nhiều upvote, đánh giá từ kết quả ngày hôm nay.
Geobits

@Geobits Tôi vẫn ngạc nhiên về điều đơn giản nhất mà tôi đã thể hiện rất tốt. Hy vọng nhiều thí sinh sẽ tham gia!
SirDarius

@SirDarius Được rồi, tốt thôi . Có một chút thử thách.
Địa chất

4

SANNbot

(một bot ủ mô phỏng trong R )

Nên gọi với Rscript SANNbot.R.

input <- strsplit(commandArgs(TRUE),split=",")[[1]]
n <- as.integer(input[1])                            # Number of players
init_s <- s <- matrix(as.integer(input[-1]),ncol=2,byrow=TRUE) # Sequence of points
totdist <- function(s){                              # Distance function
    d <- 0
    for(i in 1:99){d <- d + (abs(s[i,1]-s[i+1,1])+abs(s[i,2]-s[i+1,2]))}
    d
    }
gr <- function(s){                                   # Permutation function
    changepoints <- sample(1:100,size=2, replace=FALSE)
    tmp <- s[changepoints[1],]
    s[changepoints[1],] <- s[changepoints[2],]
    s[changepoints[2],] <- tmp
    s
    }
d <- init_d <- totdist(s)                            # Initial distance
k <- 1                                               # Number of iterations
v <- 0
t <- n*(init_d/12000)                                 # Temperature
repeat{
    si <- gr(s)                                      # New sequence
    di <- totdist(si)                                # New distance
    dd <- di - d                                     # Difference of distances
    if(dd <= 0 | runif(1) < exp(-dd/t)){             # Allow small uphill changes
        d <- di
        s <- si
        v <- v+2
        }
    k <- k+1
    if(k > 10000){break}
    if(d > init_d & v>20){s <- init_s; d <- init_d; v <- 0}
    if(v>23){break}
}
cat(paste(apply(s,1,paste,collapse=","),collapse=","))

Ý tưởng tương đối đơn giản: mỗi lượt là một "bước làm mát" của một trò chơi mô phỏng với số lượng người chơi vẫn còn trong trò chơi là "nhiệt độ" (được sửa đổi bởi khoảng cách hiện tại trên 12000, tức là khoảng cách ban đầu). Chỉ khác với một ủ mô phỏng thích hợp là tôi đã kiểm tra rằng tôi không hoán vị hơn 25 phần tử và nếu tôi sử dụng hết 20 lần di chuyển nhưng chuỗi kết quả có giá trị hơn ban đầu thì nó sẽ bắt đầu lại.


@Geobits ah xin lỗi đã xóa dòng trong đó init_s được xác định do tai nạn (cũng là "tai nạn": tôi đã thấy dòng này và nghĩ "tại sao nó lại ở đây?" Và xóa nó :)). Đã sửa.
plannapus

Tôi đã thử chương trình của bạn bằng cách sử dụng java Tourney "java Swapbot" "Rscript SANNbot.R"và nó dường như hoạt động.
plannapus

Vâng, có vẻ như bây giờ đang làm việc.
Geobits

Về lý thuyết (nếu tôi không hoàn toàn nhầm lẫn) thì nó sẽ hoạt động tốt hơn khi có nhiều người chơi tham gia trò chơi.
plannapus

Như vậy, chương trình này luôn bị tắt sớm do "quá nhiều điểm thay đổi" trong thử nghiệm của tôi. Nếu tôi tăng ugiới hạn kiểm tra lên, điều này sẽ không xảy ra (và nó hoạt động tốt hơn nhiều). Mặc dù mã của bạn có vẻ khá đơn giản, tôi không biết các yêu cầu của R vì vậy tôi không thể biết liệu logic có sai không. (phiên bản mới nhất của bộ điều khiển sẽ đưa ra thông báo về lý do tại sao bot bị tắt khi chạy Game, do đó có thể giúp xác định sự cố)
Geobits

4

BozoBot

Sử dụng logic phức tạp đằng sau Bozosort để tìm ra con đường tốt hơn. Có vẻ như thế này.

  • Hoán đổi điểm ngẫu nhiên
  • Nếu chúng tôi cải thiện
    • Trả lời câu trả lời
  • Nếu không thì
    • Thử lại

BozoBot hiện đã được cải thiện với Đa luồng ! Bốn tay sai bây giờ vô tình tung hứng các điểm cho đến khi họ vấp ngã khi cải tiến. Người đầu tiên tìm giải pháp được cookie!

Rõ ràng tôi thất bại ở đa luồng.

import java.util.Random;
public class BozoBot {
    public static String[] input;
    public static void main(String[] args) {
        input = args;
        for(int i = 0; i < 4; i++) new Minion().run();
    }
}

class Minion implements Runnable {
    public static boolean completed = false;
    public static synchronized void output(int[] x, int[] y) {
        if(!completed) {
            completed = true;
            String result = x[0]+","+y[0];
            for (int i = 1; i < 100; i++)
                result+=","+x[i]+","+y[i];
            System.out.print(result);
            // receiveCookie(); // Commented out to save money
        }
    }
    public void run() {
        String[] args = BozoBot.input[0].split(",");
        int[] x = new int[100];
        int[] y = new int[100];
        for (int i = 1; i < 201; i+=2) {
            x[(i-1)/2] = Integer.parseInt(args[i]);
            y[i/2] = Integer.parseInt(args[i+1]);
        }
        int startDistance = 0;
        for (int i = 1; i < 100; i++)
            startDistance += Math.abs(x[i-1]-x[i]) + Math.abs(y[i-1]-y[i]);
        int r1, r2, r3, r4, tX, tY, newDistance;
        Random gen = new java.util.Random();
        while (true) {
            r1 = gen.nextInt(100);
            r2 = gen.nextInt(100);
            r3 = gen.nextInt(100);
            r4 = gen.nextInt(100);
            tX = x[r1];
            x[r1] = x[r2];
            x[r2] = tX;
            tY = y[r1];
            y[r1] = y[r2];
            y[r2] = tY;
            tX = x[r3];
            x[r3] = x[r4];
            x[r4] = tX;
            tY = y[r3];
            y[r3] = y[r4];
            y[r4] = tY;
            newDistance = 0;
            for (int i=1; i < 100; i++)
                newDistance += Math.abs(x[i-1]-x[i]) + Math.abs(y[i-1]-y[i]);
            if(newDistance < startDistance)
                break;
            tX = x[r1];
            x[r1] = x[r2];
            x[r2] = tX;
            tY = y[r1];
            y[r1] = y[r2];
            y[r2] = tY;
            tX = x[r3];
            x[r3] = x[r4];
            x[r4] = tX;
            tY = y[r3];
            y[r3] = y[r4];
            y[r4] = tY;
        }
        output(x,y);
    }
}

Ehhmm ... Bạn không nên đặt tay sai của mình vào một luồng thay vì gọi run ()? AFAIK đây không phải là đa luồng ...
CommonGuy

@Manu Bạn bắt được tôi! Tôi đã cố gắng tự học và thất bại. Bất kỳ con trỏ?
Rainbolt

Tôi nghĩ rằng nó nên đượcnew Thread(new Minion()).start()
CommonGuy

1
@Manu Cảm ơn. Rõ ràng tôi chỉ đọc một nửa hướng dẫn này khi tôi đang viết mã.
Rainbolt

3

TwoSwapBot

Nâng cấp lên SwapBot, anh chàng này kiểm tra từng cặp giao dịch. Đầu tiên, anh ta kiểm tra nếu bất kỳ trao đổi duy nhất sẽ rút ngắn đường dẫn. Nếu có, nó sẽ trả lại ngay lập tức. Nếu không, anh ta kiểm tra từng cái để xem liệu một trao đổi khác sẽ rút ngắn nó. Nếu không, anh chỉ chết.

Mặc dù đường dẫn vẫn là bán ngẫu nhiên, nhưng nó thường trả về trong khoảng 100ms. Nếu anh ta phải kiểm tra mỗi 2 lần hoán đổi (khoảng 25 triệu), sẽ mất khoảng 20 giây.

Tại thời điểm nộp bài, điều này đánh bại tất cả các đối thủ khác trong các vòng thử nghiệm.

public class TwoSwapBot {

    static int numPoints = 100;

    String run(String input){
        String[] tokens = input.split(",");
        if(tokens.length < numPoints*2)
            return "bad input? nope. no way. bye.";

        Point[] points = new Point[numPoints];  
        for(int i=0;i<numPoints;i++)
            points[i] = new Point(Integer.valueOf(tokens[i*2+1]), Integer.valueOf(tokens[i*2+2]));
        int startDist = totalDistance(points);

        Point[][] swapped = new Point[(numPoints*(numPoints+1))/2][];       
        int idx = 0;
        for(int i=0;i<numPoints;i++){
            for(int j=i+1;j<numPoints;j++){
                Point[] test = copyPoints(points);
                swapPoints(test,i,j);
                int testDist = totalDistance(test);
                if( testDist < startDist)
                    return getPathString(test);
                else
                    swapped[idx++] = test;
            }
        }

        for(int i=0;i<idx;i++){
            for(int k=0;k<numPoints;k++){
                for(int l=k+1;l<numPoints;l++){
                    swapPoints(swapped[i],k,l);
                    if(totalDistance(swapped[i]) < startDist)
                        return getPathString(swapped[i]);
                    swapPoints(swapped[i],k,l);
                }
            }
        }
        return "well damn";
    }

    void swapPoints(Point[] in, int a, int b){
        Point tmp = in[a];
        in[a] = in[b];
        in[b] = tmp;
    }

    String getPathString(Point[] in){
        String path = "";
        for(int i=0;i<numPoints;i++)
            path += in[i].x + "," + in[i].y + ",";
        return path.substring(0,path.length()-1);
    }

    Point[] copyPoints(Point[] in){
        Point[] out = new Point[in.length];
        for(int i=0;i<out.length;i++)
            out[i] = new Point(in[i].x, in[i].y);
        return out;
    }

    static int totalDistance(Point[] in){
        int dist = 0;
        for(int i=0;i<numPoints-1;i++)
            dist += in[i].distance(in[i+1]);
        return dist + in[numPoints-1].distance(in[0]);
    }

    public static void main(String[] args) {
        if(args.length < 1)
            return;
        System.out.print(new TwoSwapBot().run(args[0]));
    }

    class Point{
        final int x; final int y;
        Point(int x, int y){this.x = x; this.y = y;}
        int distance(Point other){return Math.abs(x-other.x) + Math.abs(y-other.y);}
    }
}

2

Chủ đề

Bot này

  1. Chia 100 điểm thành 4 10 mảnh 25 10 điểm
  2. Bắt đầu một chủ đề cho mỗi phần
  3. Trong luồng, xáo trộn ngẫu nhiên mảng, trong khi giữ cố định điểm bắt đầu và điểm cuối
  4. Nếu khoảng cách của mảng mới ngắn hơn, hãy giữ nó
  5. Sau 59 giây, luồng chính thu thập kết quả và in ra

Ý tưởng là tìm ra sự cải tiến tốt nhất cho con đường, để các bot khác sẽ thất bại với logic của chúng.

import java.util.Arrays;
import java.util.Collections;

public class Threader {
    public static final int THREAD_COUNT = 10;
    public static final int DOT_COUNT = 100;
    private final Dot[] startDots = new Dot[THREAD_COUNT];
    private final Dot[] endDots = new Dot[THREAD_COUNT];
    private final Dot[][] middleDots = new Dot[THREAD_COUNT][DOT_COUNT/THREAD_COUNT-2];
    private final Worker worker[] = new Worker[THREAD_COUNT];
    private final static long TIME = 59000; 

    public static void main(String[] args) {
        Threader threader = new Threader();
        //remove unnecessary player count to make calculation easier
        threader.letWorkersWork(args[0].replaceFirst("^[0-9]{1,3},", "").split(","));
    }

    public void letWorkersWork(String[] args) {
        readArgs(args);
        startWorkers();
        waitForWorkers();
        printOutput();
    }

    private void readArgs(String[] args) {
        final int magigNumber = DOT_COUNT*2/THREAD_COUNT;
        for (int i = 0; i < args.length; i += 2) {
            Dot dot = new Dot(Integer.parseInt(args[i]), Integer.parseInt(args[i + 1]));
            if (i % magigNumber == 0) {
                startDots[i / magigNumber] = dot;
            } else if (i % magigNumber == magigNumber - 2) {
                endDots[i / magigNumber] = dot;
            } else {
                middleDots[i / magigNumber][(i % magigNumber) / 2 - 1] = dot;
            }
        }
    }

    private void startWorkers() {
        for (int i = 0; i < THREAD_COUNT; i++) {
            worker[i] = new Worker(startDots[i], endDots[i], middleDots[i]);
            Thread thread = new Thread(worker[i]);
            thread.setDaemon(true);
            thread.start();
        }
    }

    private void waitForWorkers() {
        try {
            Thread.sleep(TIME);
        } catch (InterruptedException e) {
        }
    }

    private void printOutput() {
        //get results
        Worker.stopWriting = true;
        int workerOfTheYear = 0;
        int bestDiff = 0;
        for (int i = 0; i < THREAD_COUNT; i++) {
            if (worker[i].diff() > bestDiff) {
                bestDiff = worker[i].diff();
                workerOfTheYear = i;
            }
        }
        //build output
        StringBuilder result = new StringBuilder(1000);
        for (int i = 0; i < THREAD_COUNT; i++) {
            result.append(startDots[i]);
            Dot middle[] = middleDots[i];
            if (i == workerOfTheYear) {
                middle = worker[i].bestMiddle;
            }
            for (int j = 0; j < middle.length; j++) {
                result.append(middle[j]);
            }
            result.append(endDots[i]);
        }
        result.replace(0, 1, ""); //replace first comma
        System.out.print(result);
    }

}

class Worker implements Runnable {

    public Dot start;
    public Dot end;
    private Dot[] middle = new Dot[Threader.DOT_COUNT/Threader.THREAD_COUNT-2];
    public Dot[] bestMiddle = new Dot[Threader.DOT_COUNT/Threader.THREAD_COUNT-2];
    public static boolean stopWriting = false;
    private int bestDist = Integer.MAX_VALUE;
    private final int startDist;

    public Worker(Dot start, Dot end, Dot[] middle) {
        this.start = start;
        this.end = end;
        System.arraycopy(middle, 0, this.middle, 0, middle.length);
        System.arraycopy(middle, 0, this.bestMiddle, 0, middle.length);
        startDist = Dot.totalDist(start, middle, end);
    }

    @Override
    public void run() {
        while (true) {
            shuffleArray(middle);
            int newDist = Dot.totalDist(start, middle, end);
            if (!stopWriting && newDist < bestDist) {
                System.arraycopy(middle, 0, bestMiddle, 0, middle.length);
                bestDist = newDist;
            }
        }
    }

    public int diff() {
        return startDist - bestDist;
    }

    private void shuffleArray(Dot[] ar) {
        Collections.shuffle(Arrays.asList(ar));
    }

}

class Dot {

    public final int x;
    public final int y;

    public Dot(int x, int y) {
        this.x = x;
        this.y = y;
    }

    public int distTo(Dot other) {
        return Math.abs(x - other.x) + Math.abs(y - other.y);
    }

    public static int totalDist(Dot start, Dot[] dots, Dot end) {
        int distance = end.distTo(start);
        distance += start.distTo(dots[0]);
        distance += end.distTo(dots[dots.length - 1]);
        for (int i = 1; i < dots.length; i++) {
            distance += dots[i].distTo(dots[i - 1]);
        }
        return distance;
    }

    @Override
    public String toString() {
        return "," + x + "," + y;
    }
}

2
Lưu ý: Tôi đã thay đổi printlnđể printthoát khỏi dòng mới ở cuối đầu ra của bạn. Nếu không thì nó bị hỏng.
Geobits

Thay đổi printlnđể printvà thực hiện các động thread-đếm. Bây giờ nó bắt đầu với 10 chủ đề ...
CommonGuy

1

Phân chia và chinh phục + Bot tham lam

LƯU Ý: Tôi đã xem mã của bạn Gamebao gồm các phần sau trong Game.parsePath:

for(int i=0;i<numPoints;i++){
        test[i] = new Point(Integer.valueOf(tokens[i*2]), Integer.valueOf(tokens[i*2+1]));
        if(test[i].equals(currentPath[i]))
            same++;

Tuy nhiên, không có catch(NumberFormatException)khối nào , vì vậy chương trình của bạn có thể sẽ bị sập khi chương trình trình phát xuất ra một chuỗi (như đã trình bày ở cuối mainphương thức của chương trình của tôi ). Tôi khuyên bạn nên sửa lỗi này, bởi vì các chương trình có thể xuất ngoại lệ, dấu vết ngăn xếp hoặc tương tự. Nếu không, hãy nhận xét dòng đó trong chương trình của tôi trước khi bạn chạy nó.

Quay lại chủ đề

Việc triển khai này (bằng Java) chia danh sách các điểm thành các khối 25, cách nhau ngẫu nhiên trong danh sách. Sau đó, nó tạo ra các luồng để rút ngắn đường đi giữa các điểm trong mỗi đoạn (Do đó, "Phân chia và chinh phục"). Các chủ đề chính giám sát những người khác và đảm bảo trình bày giải pháp ngắn nhất trong thời gian giới hạn. Nếu một luồng chết có hoặc không có giải pháp, nó sẽ bắt đầu lại một luồng khác trên một đoạn khác.

Mỗi luồng sử dụng thuật toán "tham lam", bắt đầu từ một điểm ngẫu nhiên, đi đến điểm gần nhất và lặp lại cho đến khi tất cả các điểm được bảo hiểm (Do đó, "tham lam").

Ghi chú

  • Việc này sẽ diễn ra trong toàn bộ 1 phút (Tôi đã dành 3 giây để khởi động / tắt chương trình và khởi động JVM - bạn không bao giờ biết những gì các thói quen khởi động JVM bị bắt gặp tiếp theo ...)
  • Ngay cả khi nó đã tìm thấy giải pháp, nó sẽ tiếp tục tìm kiếm và sau 1 phút, nó sẽ đưa ra giải pháp tốt nhất mà nó tìm thấy.
  • Tôi không chắc việc thực hiện này có thực sự tốt không. Tôi đã có một số niềm vui mã hóa nó mặc dù :)
  • Vì rất nhiều thứ là ngẫu nhiên, điều này có thể không cung cấp cùng một đầu ra cho cùng một đầu vào.

Chỉ cần biên dịch và sử dụng java DivideAndConquer.classđể chạy.

public class DivideAndConquer extends Thread {
    static LinkedList<Point> original;
    static Solution best;
    static LinkedList<DivideAndConquer> bots;
    static final Object _lock=new Object();

    public static void main(String[] args){
        if(args.length != 1) {
            System.err.println("Bad input!");
            System.exit(-1);
        }
        // make sure we don't sleep too long... get the start time
        long startTime = System.currentTimeMillis();
        // parse input
        String[] input=args[0].split(",");
        int numPlayers=Integer.parseInt(input[0]);
        original=new LinkedList<Point>();
        for(int i=1;i<input.length;i+=2){
            original.add(new Point(Integer.parseInt(input[i]), Integer.parseInt(input[i+1])));
        }
        // start threads
        bots=new LinkedList<DivideAndConquer>();
        for(int i=0;i<6;i++)
            bots.add(new DivideAndConquer(i));
        // sleep
        try {
            Thread.sleep(57000 - (System.currentTimeMillis() - startTime));
        } catch(Exception e){} // should never happen, so ignore
        // time to collect the results!
        Solution best=getBestSolution();
        if(best!=null){
            best.apply(original);
            String printStr="";
            for(int i=0;i<original.size();i++){
                Point printPoint=original.get(i);
                printStr+=printPoint.x+","+printPoint.y+",";
            }
            printStr=printStr.substring(0, printStr.length()-1);
            System.out.print(printStr);
        } else {
            System.out.println("Hey, I wonder if the tournament program crashes on NumberFormatExceptions... Anyway, we failed");
        }
    }

    // check the distance
    public static int calculateDistance(List<Point> points){
        int distance = 0;
        for(int i=0;i<points.size();i++){
            int next=i+1;
            if(next>=points.size())next=0;
            distance+=points.get(i).distance(points.get(next));
        }
        return distance;
    }

    public static void solutionFound(Solution s){
        // thanks to Java for having thread safety features built in
        synchronized(_lock){
            // thanks to Java again for short-circuit evaluation
            // saves lazy programmers lines of code all the time
            if(best==null || best.distDifference < s.distDifference){
                best=s;
            }
        }
    }

    public static Solution getBestSolution(){
        // make sure we don't accidentally return
        // the best Solution before it's even
        // done constructing
        synchronized(_lock){
            return best;
        }
    }

    List<Point> myPoints;
    int start;
    int length;
    int id;

    public DivideAndConquer(int id){
        super("DivideAndConquer-Processor-"+(id));
        this.id=id;
        myPoints=new LinkedList<Point>();
        start=(int) (Math.random()*75);
        length=25;
        for(int i=start;i<start+length;i++){
            myPoints.add(original.get(i));
        }
        start();
    }

    public void run(){
        // copy yet again so we can delete from it
        List<Point> copied=new LinkedList<Point>(myPoints);
        int originalDistance=calculateDistance(copied);
        // this is our solution list
        List<Point> solution=new LinkedList<Point>();
        int randomIdx=new Random().nextInt(copied.size());
        Point prev=copied.get(randomIdx);
        copied.remove(randomIdx);
        solution.add(prev);
        while(copied.size()>0){
           int idx=-1;
           int len = -1;
           for(int i=0;i<copied.size();i++){
               Point currentPoint=copied.get(i);
               int dist=prev.distance(currentPoint);
               if(len==-1 || dist<len){
                   len=dist;
                   idx=i;
               }
           }
           prev=copied.get(idx);
           copied.remove(idx);
           solution.add(prev);
        }
        // aaaand check our distance
        int finalDistance=calculateDistance(solution);
        if(finalDistance<originalDistance){
            // yes! solution
            Solution aSolution=new Solution(start, length, solution, originalDistance-finalDistance);
            solutionFound(aSolution);
        }
        // start over regardless
        bots.set(id, new DivideAndConquer(id));
    }

    // represents a solution
    static class Solution {
        int start;
        int length;
        int distDifference;
        List<Point> region;
        public Solution(int start, int length, List<Point> region, int distDifference){
            this.region=new LinkedList<Point>(region);
            this.start=start;
            this.length=length;
            this.distDifference=distDifference;
        }
        public void apply(List<Point> points){
            for(int i=0;i<length;i++){
                points.set(i+start, region.get(i));
            }
        }
    }

    // copied your Point class, sorry but it's useful...
    // just added public to each method for aesthetics
    static class Point{
        int x;
        int y;
        Point(int x, int y){
            this.x = x;
            this.y = y;
        }
        Point(Point other){
            this.x = other.x;
            this.y = other.y;
        }
        public boolean equals(Point other){
            if(this.x==other.x && this.y==other.y)
                return true;
            return false;
        }

        public int distance(Point other){
            return Math.abs(x-other.x) + Math.abs(y-other.y);
        }
    }
}

Bạn có thể tin được không? SX yêu cầu tôi cho một captcha khi tôi gửi này! Điều này có vẻ bot-made cho bạn? Nghiêm túc?
DankMeme

1
Sửa lỗi cho đẩy ngoại lệ. Bây giờ nó sẽ chỉ giết người chơi thay vì giết chương trình.
Geobits

Đối với hồ sơ, tôi không nghĩ rằng nó đã bị sập trên dòng " Hey, tôi tự hỏi nếu ... " nào. Nó kiểm tra nếu có <200mã thông báo trước khi thử phân tích cú pháp. Vẫn tốt hơn để kiểm tra cho nó anyway.
Geobits

@Geobits haha ​​đã không nhận ra điều đó
DankMeme

Lưu ý: Để có được điều này để biên dịch, tôi đã phải thêm một )dòng trên 19; đổi substrsang substringngày 38; khởi tạo idxmột cái gì đó trong run()phương thức.
Geobits
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.