Sıcak Patates Satıcısı


23

Bir nokta listesi göz önüne alındığında, tüm noktaları ziyaret eden ve başlangıç ​​noktasına geri dönen en kısa yolu bulun.

Gezgin satıcı problemi olarak / hesaplamak bunu yaklaşmak için birçok yol vardır, bilgisayar bilimi alanında iyi bilinmektedir. Çok büyük nokta grupları için çözüldü, ancak en büyüğünün bazılarının işlemciliği yıllarca alması gerekiyor.

Patates tarafından yakılma.

Sıcak Patates , müzik çalarken 2+ oyuncunun bir dairenin etrafında bir "patates" geçtiği bir oyundur. Amaç hızlıca bir sonraki oyuncuya aktarmaktır. Müzik durduğunda patatesi tutuyorsanız, dışarı çıkarsınız.


Amacı, sıcak Patates Salesman olduğu:

100 benzersiz nokta kümesi göz önüne alındığında , bu noktaları daha iyi bir sırayla döndürün ( aşağı doğru tanımlandığı gibi daha kısa toplam mesafe ). Bu, sorunu bir sonraki oyuncuya "iletir". Geliştirmeleri ve diğerine geçirmeleri vb. Gerekir. Bir oyuncu iyileştiremezse, dışarı çıkar ve bir oyuncu kalana kadar oynamaya devam eder.

Bunun bir “kaba-güç-beni-bir-yol” yarışması olmasını engellemek için şu şartlar var:

  • Patatesi geçmek için bir dakikadan fazla zaman geçiremezsiniz. Bir dakika doluncaya kadar daha kısa bir çözüm bulamadıysanız ve geçmediyseniz, çıkardınız.

  • 25 noktadan fazla konumunu değiştiremezsiniz . Kesin olarak >= 75puanlar, aldıklarınızla aynı konumda olmalıdır. Hangisini değiştirmeye karar verdiğiniz önemli değil , yalnızca değiştirdiğiniz tutar .

Sadece bir oyuncu kaldığında, o oyunun galibi olur ve bir puan alır. Turnuva , oyuncu sayısının 5*nbulunduğu oyunlardan oluşur n. Her oyun, başlangıç ​​oyuncusu döndürülecek ve kalan oyuncu sırası karıştırılacaktır . Sonunda en yüksek puana sahip oyuncu turnuvayı kazanır. Turnuva ilk etapta bir kravatla sona ererse, yalnızca bu yarışmacılarla yeni bir turnuva oynanacaktır. Bu, kravat yok olana kadar devam edecek.

Her oyun için başlangıç ​​oyuncusu, belirli bir düzende olmayan bir takım sahte seçili puan alır.

Noktalar, x,ykartezyen ızgara üzerinde bir çift ​​tam sayı koordinatı olarak tanımlanır . Mesafe kullanılarak ölçülür Manhattan mesafe , |x1-x2| + |y1-y2|. Tüm koordinatlar [0..199]aralıkta yer alacaktır .

Giriş

Giriş, tek bir dize argümanı ile verilir. Mevcut oyuncu sayısını ( m) ve 100 puanı temsil eden 201 virgülle ayrılmış tam sayıdan oluşacaktır :

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

Bu noktaların sırası, geçerli yoldur. Toplam mesafe, her noktadan diğerine uzaklık eklenerek elde edilir ( dist(0,1) + dist(1,2) + ... + dist(99,0)). Toplam mesafeyi hesaplarken başlamaya geri dönmeyi unutmayın!

Not molduğu değil oyun başladıktan oyuncu sayısı, bu hala bir sayıdır.

Çıktı

Çıktı, giriş eksi ile aynı şekilde verilir m; noktaları yeni sıralarında temsil eden virgülle ayrılmış tam sayıları içeren tek bir dize.

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

Kontrol programı yalnızca bir dakika çıktısını bekleyecektir. Çıktı alındığında, şunu doğrulayacaktır:

  • çıktı iyi şekillendirilmiş
  • çıkış sadece ve girişte mevcut olan tüm 100 noktadan oluşur.
  • >=75 puanlar orijinal konumlarındadır
  • yol uzunluğu önceki yoldan daha az

Bu kontrollerden herhangi biri başarısız olursa (veya herhangi bir çıktı yoksa), siz yok sayılırsınız ve oyun bir sonraki oyuncuya geçer.

Kontrol programı

Kontrol programını bu linkte bulabilirsiniz . Kontrol programının kendisi belirleyicidir ve kukla bir tohum ile birlikte gönderilir 1. Puanlama sırasında kullanılan tohumlar farklı olacaktır, bu yüzden tükettiği sıra sıralarını / nokta listelerini analiz etmeye çalışmaktan rahatsız olmayın.

Ana sınıftır Tourney. Bunu yapmak, yarışmacıların argüman olarak verilmiş olduğu turnuvaya katılacak. Her oyunun kazananı ve sonunda bir taksitli tükürür. İki SwapBots içeren örnek turnuvaya benziyor:

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

Bir seferde sadece bir oyun test etmek istiyorsanız, Gamebunun yerine sınıfı çalıştırabilirsiniz . Bu, argüman olarak verilen sırayla oyuncularla bir oyun oynayacaktır. Varsayılan olarak, geçerli oynatıcıyı ve yol uzunluğunu gösteren bir oyun oynatma da basar.

Ayrıca dahil birkaç deneme oyuncular şunlardır: SwapBot, BlockPermuterve TwoSwapBot. İlk ikisi puanlama çalışmalarına dahil edilmeyecek, test sırasında bunları kullanmaktan ve kötüye kullanmaktan çekinmeyin. Yargılamaya dahil TwoSwapBot olacak ve o huysuz değil, bu yüzden A oyununu getir.

derleme

  • Durum bilgilerini kaydedemezsiniz ve her bir dönüş programınızın ayrı bir çalışmasıdır. Her bir dönüş alacağınız tek bilgi puan setidir.

  • Dış kaynakları kullanamazsınız. Buna şebeke aramaları ve dosya erişimi de dahildir.

  • TSP problemini veya varyantlarını çözmek / yardımcı olmak için tasarlanmış kütüphane fonksiyonlarını kullanamazsınız.

  • Diğer oyuncularla hiçbir şekilde manipülasyon yapamaz veya bunlara müdahale edemezsiniz.

  • Kontrol programını veya içerdiği sınıfları veya dosyaları herhangi bir şekilde manipüle edemez veya müdahale edemezsiniz.

  • Çok diş açmaya izin verilir.

  • Kullanıcı başına bir başvuru. Birden fazla giriş yaparsanız, sadece gönderilen ilk girişi girerim. Gönderinizi değiştirmek istiyorsanız, orijinali düzenleyin / silin.

  • Turnuva 13.04 Ubuntu'da, i7-3770K CPU ve 16GB RAM'e sahip bir bilgisayarda yapılacak . Bir VM'de çalıştırılmayacaktır. Kötü niyetli olarak algıladığım her şey mevcut ve gelecekteki girişlerinizi derhal diskalifiye eder .

  • Tüm girişler komut satırından ücretsiz ( biradaki gibi ) yazılımı ile çalıştırılabilir olmalıdır . Girişinizi derlerken / çalıştırırken sorun yaşarsam yorumlarda yardım isteyeceğim. Cevap vermezseniz ya da sonunda çalıştıramazsam, diskalifiye edilir.

Sonuçlar (22 Mayıs 2014)

Yeni sonuçlar geldi! UntangleBot rekabeti oldukça sağlam bir şekilde yendi. TwoSwapBot yedi kazancı yönetti ve SANNbot da bir zafer kazandı. İşte bir çetele ve ham çıktıya bir link :

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

Haliyle şimdi , UntangleBot onay işaretini kazandı. Ancak turnuvaya katılacağım için daha fazla yarışmacı belirdiği ve kabul edilen cevabı buna göre değiştirdiğim için bunun size girmekten caydırmasına izin vermeyin.


Yorum temizlendi. Kayıp olası herhangi bir bilgi için lütfen bana bildirin.
Doorknob

Dostum bu zorluğun neden final sınavlarım sırasında olması gerekti (nihayet okul yeay ile yapıldı) Eminim ki kötü bir planlamacı Geobits;) O zamanlar çok garip / ne yazık ki, bir sürü kral sorusu vardı ve şimdi hiç yok (belki bir seferde sadece bir tane varsa daha iyi çalışır) ipucu) ...
Herjan

@Herjan Mevcut şampiyonla mücadele etmeye çalışmaktan çekinmeyin. Yeni yarışmacılar göründükleri gibi yarışma değil bu yüzden, tekrar turnuva kaçıyorum üzerinde ya da bir şey. SirDarius'u yendikten sonra, kendinize veya bir başkasına sizinkini dövmek ve hayatını yeniden içine çekmek için teşvik edebilir;)
Geobits

@Herjan Lütfen bir giriş yapın! Burada iyileştirme için çok yer olduğuna inanıyorum. Buradaki çözümlerin çoğu, benimki dahil, bu soruna özgü akıllı algoritmalara dayanmıyor.
SirDarius

Değişiklik sınırlamasıyla ilgili bir sorun olduğunu düşünüyorum. Bazı zamanlar daha iyi bir çözüm elde etmek için tüm veri setini değiştirmek gerekecektir.
Ilya Gazman

Yanıtlar:


8

UntangleBot (eski adıyla NiceBot)

İki strateji kullanan bir C ++ 11 botu.
İlk başta 25 noktadan daha yakın yollar arasındaki kavşakları tespit ederek, mümkünse yolu "çözmeye" çalışacaktır (çünkü karışma işlemi aradaki tüm noktaları değiştirmeyi gerektirdiğinden).
İlk strateji başarısız olursa, daha iyi bir yol bulunana kadar daha iyi mesafeler bulmak için rastgele noktaları değiştirir.

Bu bot sürekli olarak TwoSwapBot'u test turnuvalarımdaki bir mağlubiyet için yaklaşık beş galibiyet oranıyla atıyor.

// 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;
}

Beni 19 dakikada yendin!
Rainbolt

Bu, bugünün sonuçlarından yola çıkarak daha fazla oyuna sahip olmalı.
Geobits

@Geobits Karşılaştığım en basit şeyi hala çok iyi performansa şaşırttım. Daha zorlu yarışmacılar umuduyla girecek!
SirDarius

@ SirDarius Tamam, iyi . Bir var zorluk biraz.
Geobits

4

SANNbot

( R'de benzetilmiş bir tavlama botu )

İle çağrılmalıdır 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=","))

Fikir göreceli olarak basit: Her bir dönüş hala oyunda bulunan oyuncu sayısı ile “sıcaklık” olarak ayarlanmış bir tavlama işleminin bir "soğutma basamağı" ( 12000 üzerindeki mevcut mesafe tarafından değiştirildi, yani kabaca başlangıç ​​mesafesi). Uygun bir benzetimli tavlama ile yalnızca fark, 25 öğeden daha fazla elemana izin vermediğimi kontrol etmem ve 20 hamle kullanmam durumunda ortaya çıkan dizilimin başlangıç ​​değerinden daha değerli olduğunu kontrol etmek.


@Geobits ah üzgünüm init_s 'in kazayla tanımlandığı satırı sildi (peki "kaza": çizgiyi gördüm ve "neden yine burada?" Diye düşündüm :)). Düzeltildi.
plannapus

Programınızı kullanarak denedim java Tourney "java Swapbot" "Rscript SANNbot.R"ve işe yarayacak gibiydi.
plannapus

Evet, şimdi çalışıyor gibi görünüyor.
Geobits

Teoride (tamamen yanılmıyorsam) oyuna daha fazla oyuncu girdiğinde daha iyi performans göstermeli.
plannapus

Olduğu gibi, bu program testimdeki "çok fazla puan değişti" nedeniyle her zaman erken gidiyor. Eğer ukontrol sınırlarını aşarsam, bu olmaz (ve çok daha iyi performans gösterir). Kodunuz oldukça basit gibi görünse de, R'nin tuhaflıklarını bilmiyorum bu yüzden mantığın yanlış olup olmadığını söyleyemem. (Kontrol ünitesinin en son sürümü, bir botun çalışırken neden dışarı çıktığı konusunda mesajlar verecektir Game, bu sayede problemi tam olarak belirlemenize yardımcı olabilir)
Geobits

4

BozoBot

Daha iyi bir yol bulmak için Bozosort'un arkasındaki karmaşık mantığı kullanır . Bu gibi görünüyor.

  • Rastgele noktaları değiştir
  • Eğer gelişirsek
    • Cevabını iade et
  • Aksi takdirde
    • Tekrar deneyin

BozoBot şimdi Multithreading ile geliştirildi ! Şimdi dört köle, amaçsızca bir şekilde hokkabazlık yaparak bir gelişme gösterene dek işaret ediyor. Bir çözüm bulan ilk kişi bir çerez alır!

Görünüşe göre ben çok okuyuculuk başarısız.

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 ... Kölelerini run () çağırmak yerine bir iş parçacığına koymalı mıydın? AFAIK bu okuyuculu değil ...
CommonGuy

@Manu Beni yakaladın! Kendi başıma öğrenmeye çalıştım ve başaramadım. Herhangi bir işaretçi var mı?
Rainbolt

Olması gerektiğini düşünüyorumnew Thread(new Minion()).start()
CommonGuy

1
@Manu Teşekkürler. Görünüşe göre kod yazarken bu yazının sadece yarısını okudum .
Rainbolt

3

TwoSwapBot

Bir yükseltme SwapBot, bu adam her takas çiftini kontrol eder. İlk önce, herhangi bir takasın yolu kısaltıp kısmayacağını kontrol eder. Olursa hemen döner. Aksi takdirde, başka bir takas işleminin kısaltıp kısmayacağını görmek için her birini kontrol eder . Olmazsa, sadece ölür.

Yol hala yarı rasgele olsa da, normal olarak yaklaşık 100 ms'de geri döner. Her 2 swap'ı (kabaca 25M) kontrol etmesi gerekiyorsa, yaklaşık 20 saniye sürer.

Teslim anında, bu diğer rakipleri test turlarında yendi.

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

pafta

Bu bot

  1. 100 sayıyı 4 10 adet 25 10 sayıya böler
  2. Her parça için bir iplik başlatır
  3. İplikte, başlangıç ​​ve bitiş noktalarını sabit tutarken rastgele diziyi karıştırın
  4. Yeni dizinin mesafesi kısaysa,
  5. 59 saniye sonra ana iplik sonuçları toplar ve yazdırır

Fikir, yoldaki en iyi gelişmeyi bulmak, böylece diğer botlar mantıklarıyla başarısız olacak.

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
Not: Değiştim printlniçin printçıktınıza sonunda yeni satır kurtulmak için. Aksi halde çöker.
Geobits

Değişti printlniçin printve ilmekli dinamiğini yaptı. Şimdi 10 konu başlıyor ...
CommonGuy

1

Böl Ve Conquer + Açgözlü Bot

NOT: Ben için kod baktım GameGame.parsePath aşağıdaki içeren:

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++;

Ancak, catch(NumberFormatException)blok yoktur , dolayısıyla bir oynatıcı programı bir dizge çıkardığında programınız çökecektir (programımın mainmetodunun sonunda gösterildiği gibi ). Bunu düzeltmenizi öneririm, çünkü programlar istisnalar, yığın izleri veya benzeri şeyler verebilir. Aksi halde, çalıştırmadan önce programımdaki bu satırı yorumlayın.

Konuya geri dön

Bu uygulama (Java’da), listeyi rastgele aralıklarla yerleştirilen 25’lik parçalara ayırır. Daha sonra, her bir yığıntaki noktalar arasındaki yolu kısaltmak için iplikler yaratır (Dolayısıyla, "Böl ve Conquer"). Ana iplik diğerlerini izler ve en kısa çözümü zaman içinde sunmayı sağlar. Eğer bir iplik çözelti ile veya çözülmeden ölürse, başka bir iplikten farklı bir öbek üzerinde tekrar başlar.

Her iş parçacığı rastgele bir noktadan başlayan "açgözlü" algoritmayı kullanır, en yakın noktaya gider ve tüm noktalar kaplanana kadar tekrar eder (Dolayısıyla, "açgözlü").

notlar

  • Bu tam 1 dakika boyunca sürecek (program başlatma / kapatma ve JVM başlangıcı için 3 saniye verdim - JVM başlangıç ​​yordamlarının bir sonraki adımda ne yakalayacağını asla bilemezsiniz ...)
  • Çözüm bulsa bile, aramaya devam edecek ve 1 dakika sonra bulduğu en iyi çözümü sunacaktır.
  • Bu uygulamanın gerçekten iyi olup olmadığından emin değilim. Ama kodlama biraz eğlendim :)
  • Bir çok şey rastgele olduğundan, bu aynı girdi için aynı çıktıyı vermeyebilir.

Sadece derleyin ve java DivideAndConquer.classçalıştırmak için kullanın .

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);
        }
    }
}

Buna inanabiliyor musun? SX bunu teslim ettiğimde bir captcha istedi ! Bu sana bot yapımı görünüyor mu? Ciddi anlamda?
DankMemes 14:14

1
NFException için düzeltme itti. Şimdi programı öldürmek yerine sadece oyuncu öldürecek.
Geobits

Kayıt için, yine de " Hey, merak ediyorum ... " hattına düşeceğini sanmıyorum . <200Ayrıştırmaya çalışmadan önce belirteçlerin olup olmadığını kontrol eder . Yine de kontrol etmek daha iyi.
Geobits

@ Geobits haha ​​bunun farkında değildi
DankMemes

Not: Bunu derlemek için, )19. satıra bir satır eklemek zorunda kaldım ; değiştirmek substriçin substring38 üzerinde; başlatmak idxyılında şeye run()yöntemle.
Geobits
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.