हॉट आलू सेल्समैन


23

बिंदुओं की सूची को देखते हुए, सबसे छोटा रास्ता खोजें जो सभी बिंदुओं पर जाता है और शुरुआती बिंदु पर लौटता है।

यात्रा विक्रेता की समस्या कंप्यूटर विज्ञान के क्षेत्र में अच्छी तरह से जाना जाता है, के रूप में गणना / यह अनुमान लगाने के लिए कई तरीके हैं। इसे अंकों के बहुत बड़े समूहों के लिए हल किया गया है, लेकिन कुछ सबसे बड़े सीपीयू-वर्षों को समाप्त करने के लिए लेते हैं।

आलू से जला मत करो।

हॉट पोटैटो एक ऐसा खेल है जिसमें 2+ खिलाड़ी एक "आलू" एक सर्कल में चारों ओर से गुजरते हैं, जबकि संगीत बजाते हैं। ऑब्जेक्ट इसे अगले खिलाड़ी को जल्दी से पास करना है। यदि आप संगीत बंद होने पर आलू पकड़ रहे हैं, तो आप बाहर हैं।


हॉट आलू सेल्समैन का उद्देश्य है:

100 अनूठे बिंदुओं के एक सेट को देखते हुए , उन बिंदुओं को बेहतर क्रम में लौटाएं ( आगे की ओर नीचे की ओर कम दूरी )। यह अगले खिलाड़ी के लिए समस्या को "पास" कर देगा। उन्हें इसे सुधारना होगा और इसे अगले पास करना होगा, आदि। यदि कोई खिलाड़ी इसमें सुधार नहीं कर सकता है, तो वे आउट होते हैं और खेलते रहते हैं जब तक कि एक खिलाड़ी शेष न हो।

इसे "ब्रूट-फोर्स-मी-ए-पाथ" प्रतियोगिता होने से रोकने के लिए, ये वजीफे हैं:

  • आलू को पास करने में आपको एक मिनट से ज्यादा नहीं लग सकता है । यदि आपने एक मिनट भी कम समय तक नहीं पाया है और एक छोटा सा उपाय किया है, तो आप बाहर हैं।

  • आप 25 से अधिक बिंदुओं की स्थिति नहीं बदल सकते । सटीक होने के लिए, >= 75अंक उसी स्थिति में होना चाहिए , जब आप उन्हें प्राप्त कर चुके हों। इससे कोई फर्क नहीं पड़ता है कि आप किन लोगों को बदलने का फैसला करते हैं, बस आप कितनी राशि बदलते हैं।

जब केवल एक खिलाड़ी को छोड़ दिया जाता है, तो वह उस गेम का विजेता होता है, और एक अंक प्राप्त करता है। एक टूमनी में 5*nखेल होते हैं , जहां nखिलाड़ियों की संख्या होती है। प्रत्येक खेल, शुरुआती खिलाड़ी को घुमाया जाएगा , और शेष खिलाड़ी के आदेश को बदल दिया जाएगा । अंत में सबसे अधिक अंक पाने वाला खिलाड़ी टूमनी का विजेता होता है। यदि टूरनी पहले स्थान पर टाई के साथ समाप्त होता है, तो केवल उन प्रतियोगियों के साथ एक नया टूर्नामेंट खेला जाएगा। यह तब तक जारी रहेगा जब तक कोई टाई न हो।

प्रत्येक गेम के लिए शुरुआती खिलाड़ी बिना किसी विशेष क्रम के छद्म रूप से चयनित बिंदुओं का एक सेट प्राप्त करेगा।

अंक x,yएक कार्टियरियन ग्रिड पर पूर्णांक निर्देशांक की एक जोड़ी के रूप में परिभाषित किए गए हैं । दूरी का उपयोग कर मापा जाता है मैनहट्टन दूरी , |x1-x2| + |y1-y2|। सभी निर्देशांक [0..199]सीमा में होंगे।

इनपुट

इनपुट एकल स्ट्रिंग तर्क के साथ दिया गया है। इसमें मौजूदा खिलाड़ियों की संख्या ( m) और 100 अंकों का प्रतिनिधित्व करने वाले 201 अल्पविराम से अलग पूर्णांक शामिल होंगे :

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

इन बिंदुओं का क्रम वर्तमान पथ है। प्रत्येक बिंदु से अगले ( dist(0,1) + dist(1,2) + ... + dist(99,0)) तक की दूरी को जोड़कर कुल दूरी प्राप्त की जाती है । कुल दूरी की गणना करते समय शुरू करने के लिए वापस जाने के लिए मत भूलना!

ध्यान दें कि mहै नहीं खिलाड़ियों है कि खेल शुरू कर दिया की संख्या, यह नंबर है कि अभी भी में हो रहा है।

उत्पादन

आउटपुट उसी तरह दिया जाता है जैसे इनपुट, माइनस m; अल्पविराम से अलग किए गए एकल तार को उनके नए क्रम में बिंदुओं का प्रतिनिधित्व करने वाले पूर्णांक।

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

नियंत्रण कार्यक्रम केवल एक मिनट के लिए आउटपुट का इंतजार करेगा। जब आउटपुट प्राप्त होता है, तो यह सत्यापित करेगा कि:

  • आउटपुट अच्छी तरह से बनता है
  • आउटपुट में केवल और सभी 100 बिंदु होते हैं जो इनपुट में मौजूद होते हैं
  • >=75 अंक उनके मूल पदों में हैं
  • पथ की लंबाई पिछले पथ से कम है

यदि इनमें से कोई भी चेक विफल हो जाता है (या कोई आउटपुट नहीं है), तो आप बाहर हैं और खेल अगले खिलाड़ी के लिए आगे बढ़ेगा।

नियंत्रण कार्यक्रम

आप इस लिंक पर नियंत्रण कार्यक्रम पा सकते हैं । नियंत्रण कार्यक्रम स्वयं नियतात्मक है, और डमी बीज के साथ पोस्ट किया गया है 1। स्कोरिंग के दौरान इस्तेमाल किया जाने वाला बीज अलग होगा, इसलिए इसे मोड़ने वाले टर्न ऑर्डर / पॉइंट लिस्ट का विश्लेषण करने की कोशिश न करें।

मुख्य वर्ग है Tourney। इसे चलाने वाले तर्क के रूप में दिए गए प्रतियोगियों के साथ एक पूर्ण टूर्नामेंट करेंगे। यह अंत में प्रत्येक खेल के विजेता और एक टैली को बाहर निकालता है। दो स्वैबोट्स के साथ एक नमूना टूमनी जैसा दिखता है:

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

यदि आप एक बार में सिर्फ एक गेम का परीक्षण करना चाहते हैं, तो आप Gameइसके बजाय कक्षा चला सकते हैं । यह तर्क के रूप में दिए गए क्रम में खिलाड़ियों के साथ एक गेम चलाएगा। डिफ़ॉल्ट रूप से, यह वर्तमान खिलाड़ी और पथ की लंबाई दिखाते हुए एक प्ले-बाय-प्ले भी प्रिंट करेगा।

भी शामिल कुछ परीक्षण खिलाड़ी हैं: SwapBot, BlockPermuter, और TwoSwapBot। पहले दो रन स्कोरिंग में शामिल नहीं होंगे, इसलिए परीक्षण के दौरान उनका उपयोग और दुरुपयोग करने के लिए स्वतंत्र महसूस करें। TwoSwapBot को शामिल करने में शामिल किया जाएगा , और वह कोई भी कमी नहीं है, इसलिए अपना ए-गेम लाएं।

मिश्रण

  • आप राज्य की जानकारी नहीं बचा सकते हैं, और प्रत्येक मोड़ आपके प्रोग्राम का एक अलग रन है। प्रत्येक मोड़ पर आपको प्राप्त होने वाली एकमात्र जानकारी अंकों का समूह है।

  • आप बाहरी संसाधनों का उपयोग नहीं कर सकते। इसमें नेटवर्क कॉल और फ़ाइल एक्सेस शामिल है।

  • आप TSP समस्या या इसके वेरिएंट के साथ हल / सहायता के लिए डिज़ाइन किए गए लाइब्रेरी फ़ंक्शंस का उपयोग नहीं कर सकते।

  • आप किसी भी तरह से अन्य खिलाड़ियों के साथ छेड़छाड़ या हस्तक्षेप नहीं कर सकते।

  • आप नियंत्रण कार्यक्रम या किसी भी तरह से शामिल वर्गों या फ़ाइलों के साथ हेरफेर या हस्तक्षेप नहीं कर सकते।

  • मल्टी-थ्रेडिंग की अनुमति है।

  • प्रति उपयोगकर्ता एक सबमिशन। यदि आप एक से अधिक प्रविष्टि जमा करते हैं, तो मैं केवल पहले एक प्रविष्टि दर्ज करूंगा। यदि आप अपना सबमिशन बदलना चाहते हैं, तो मूल को संपादित / हटाएं।

  • टूर्नामेंट एक कंप्यूटर पर i7-3770K सीपीयू और 16 जीबी रैम के साथ, उबंटू 13.04 पर चल रहा होगा । यह एक वीएम में नहीं चलाया जाएगा। मुझे जो कुछ भी दुर्भावनापूर्ण लगता है, वह आपके द्वारा प्रस्तुत वर्तमान और भविष्य की प्रविष्टि को अयोग्य घोषित कर देगा।

  • सभी प्रविष्टियों को कमांड लाइन से फ्री ( बीयर में ) सॉफ्टवेयर के साथ चलाया जाना चाहिए । अगर मुझे आपकी प्रविष्टि को संकलित / चलाने में समस्या है, तो मैं टिप्पणियों में सहायता का अनुरोध करूंगा। यदि आप जवाब नहीं देते हैं या मैं अंततः इसे नहीं चला सकता हूं, तो यह अयोग्य होगा।

परिणाम (22 मई 2014)

नए परिणाम में हैं! अनटंगलबोट ने प्रतियोगिता को काफी शानदार ढंग से हराया है। TwoSwapBot ने सात जीत हासिल कीं, और SANNbot ने इसमें भी जीत हासिल की। यहाँ एक स्कोरबोर्ड है, और कच्चे आउटपुट का लिंक है :

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

जैसा कि यह अब खड़ा है , अनटंगलबोट ने चेकमार्क जीता है। हालांकि, आपको प्रवेश करने से हतोत्साहित न करें, हालांकि, चूंकि मैं टूर्नामेंट को चलाऊंगा, क्योंकि अधिक प्रतियोगी दिखाई देंगे और तदनुसार स्वीकृत उत्तर को बदल देंगे।


टिप्पणियाँ शुद्ध। कृपया मुझे किसी भी संभावित खो जानकारी के लिए सूचित करें।
डोरकनॉब

मनुष्य को यह चुनौती मेरी अंतिम परीक्षाओं (आखिरकार, स्कूल की हाँ के साथ) के दौरान क्यों लेनी पड़ी। आपको यकीन है कि एक बुरा योजनाकार जियोबिट्स हैं;) अजीब / दुख की बात है कि उस समय वहां राजा-टन के पहाड़ी सवाल थे और अब कोई भी नहीं है (शायद यह बेहतर काम करता है यदि एक समय में केवल एक ही संकेत हो, संकेत) ...
हरजन

@ हिरण वर्तमान शैंपू से निपटने की कोशिश करने के लिए स्वतंत्र महसूस करें। जैसे ही नए प्रतियोगी सामने आएंगे, मैं फिर से टूर्नी चलाऊंगा, इसलिए यह प्रतियोगिता खत्म नहीं हुई है। सिरडारियस को मारो और यह उसे या किसी और को पीटने के लिए प्रेरित कर सकता है, जीवन को वापस सांस लेना;)
Geobits

@ हरण कृपया एक प्रविष्टि जमा करें! मेरा मानना ​​है कि यहां सुधार की बहुत गुंजाइश है। यहां अधिकांश समाधान, जिनमें मेरा भी शामिल है, इस समस्या के लिए विशिष्ट चतुर एल्गोरिदम पर भरोसा नहीं करते हैं।
सिडराइडर

मुझे लगता है कि संशोधन सीमा के साथ एक समस्या है। बेहतर समाधान पाने के लिए डेटा के पूरे सेट को संशोधित करने में कुछ समय लगेगा।
इल्या गज़मैन

जवाबों:


8

अनटंगलबोट (पूर्व में नाइसबोट)

एक C ++ 11 बॉट जो दो रणनीतियों का उपयोग करता है।
पहले तो यह संभव हो सकता है, यदि संभव हो तो पथ को "अनटंगल" करने की कोशिश करें, 25 से अधिक बिंदुओं के बीच के रास्तों का पता लगाकर (क्योंकि असंगति का अर्थ है सभी बिंदुओं के बीच में संशोधन करना)।
यदि पहली रणनीति विफल हो जाती है, तो यह बेतरतीब ढंग से स्वैप करता है जब तक कि बेहतर पथ नहीं मिला हो।

यह बॉट लगातार मेरे टेस्ट टूरनीज में एक हार के लिए पांच जीत के अनुमानित अनुपात के साथ टूस्वेबॉट को हराता है।

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

आपने मुझे 19 मिनट तक हराया!
बारिश का समय

आज के परिणामों को देखते हुए, इसमें और अधिक वृद्धि होनी चाहिए।
भूगोल

@Geobits मैं अभी भी सबसे सरल बात हैरान हूं, जो मैंने इतने अच्छे प्रदर्शन के साथ किया। अधिक चुनौतीपूर्ण प्रतियोगियों में प्रवेश करेंगे!
सिमरडीयर

@ शर्दी ओके, ठीक है । एक है चुनौती का सा।
Geobits

4

SANNbot

( आर में एक नकली एनीलिंग बॉट )

के साथ बुलाया जाना चाहिए 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=","))

विचार अपेक्षाकृत सरल है: प्रत्येक बारी के एक एक की "ठंडा कदम" है नकली annealing "तापमान" (12000 से अधिक वर्तमान दूरी के द्वारा संशोधित किया, यानी मोटे तौर पर प्रारंभिक दूरी) के रूप में खेल में अभी भी खिलाड़ियों की संख्या के साथ। केवल एक उचित सिम्युलेटेड एनेलिंग के साथ अंतर यह है कि मैंने जाँच की है कि मैं 25 से अधिक तत्वों की अनुमति नहीं देता हूं और अगर मैंने 20 चालों का उपयोग किया है लेकिन परिणामी अनुक्रम प्रारंभिक की तुलना में लायक है तो यह फिर से शुरू होता है।


@Geobits आह सॉरी ने उस लाइन को हटा दिया जहां init_s को दुर्घटना से परिभाषित किया गया था (अच्छी तरह से "दुर्घटना": मैंने रेखा को देखा और सोचा कि "यह यहां फिर से क्यों है?" और इसे हटा दिया :))। सही किया।
प्लेनैपस

मैंने आपके कार्यक्रम का उपयोग करने की कोशिश की java Tourney "java Swapbot" "Rscript SANNbot.R"और यह काम करने लगा।
प्लेनैपस

हाँ, यह अब काम करने लगता है।
ज्योबिट्स

सिद्धांत रूप में (यदि मैं पूरी तरह से गलत नहीं हूं) तो बेहतर प्रदर्शन करना चाहिए जब अधिक खिलाड़ी खेल में प्रवेश करें।
प्लेनैपस

जैसा कि, यह कार्यक्रम हमेशा मेरे परीक्षण में "बहुत सारे बिंदुओं में परिवर्तन" के कारण जल्दी निकल जाता है। अगर मैं uचेक सीमा से टकराता हूं , तो ऐसा नहीं होता (और यह बहुत बेहतर प्रदर्शन करता है)। जबकि आपका कोड बहुत सीधा लगता है, मुझे नहीं पता कि आर की quirks है इसलिए मैं नहीं बता सकता कि क्या तर्क गलत है। (नियंत्रक का नवीनतम संस्करण इस बारे में संदेश देगा कि एक बॉट बाहर निकलते समय क्यों चलता है Game, ताकि समस्या को इंगित करने में मदद मिल सके)
जियोबिट्स

4

BozoBot

बेहतर रास्ता खोजने के लिए बोज़ोसॉर्ट के पीछे जटिल तर्क का उपयोग करता है । यह इस तरह दिख रहा है।

  • यादृच्छिक अंक स्वैप करें
  • अगर हम सुधर गए
    • उत्तर लौटा दो
  • अन्यथा
    • पुनः प्रयास करें

BozoBot को अब Multithreading से बेहतर बनाया गया है ! चार मिनट अब लक्ष्यहीनता से अंकुश लगाते हैं जब तक कि वे एक सुधार पर ठोकर नहीं खाते। पहले एक समाधान खोजने के लिए एक कुकी मिलती है!

जाहिर है मैं मल्टीथ्रेडिंग में विफल रहता हूं।

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

एह्म्म ... क्या आपको रनिंग () को कॉल करने के बजाय अपने minions को एक धागे में नहीं बांधना चाहिए? AFAIK यह मल्टीथ्रेडिंग नहीं है ...
कॉमनग्यू

@ मनु तुमने मुझे पकड़ लिया! मैंने इसे अपने दम पर सीखने की कोशिश की और असफल रहा। कोई संकेत?
बारिश

मुझे लगता है कि यह होना चाहिएnew Thread(new Minion()).start()
कॉमनग्यू

1
@ मनु धन्यवाद। जाहिरा तौर पर मैं इस ट्यूटोरियल का केवल आधा हिस्सा पढ़ता था जब मैं कोडिंग करता था।
बारिश

3

TwoSwapBot

अपग्रेड करने के लिए SwapBot, यह लड़का स्वैप की प्रत्येक जोड़ी के लिए जाँच करता है। पहले, वह जाँच करता है कि क्या कोई एकल स्वैप मार्ग को छोटा कर देगा। यदि ऐसा होता है, तो यह तुरंत वापस आ जाता है। यदि नहीं, तो वह प्रत्येक को यह देखने के लिए जांचता है कि क्या एक और स्वैप इसे छोटा करेगा। यदि नहीं, तो वह मर जाता है।

जबकि पथ अभी भी अर्ध-यादृच्छिक है, यह आमतौर पर लगभग 100ms में लौटता है। अगर उसे हर 2-स्वैप (लगभग 25M) की जाँच करनी है, तो लगभग 20 सेकंड लगते हैं।

सबमिशन के समय, इसने टेस्ट राउंड में अन्य सभी प्रतियोगियों को हराया।

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

threader

यह बॉट

  1. 25 10 अंक के 4 10 टुकड़ों में 100 अंकों को विभाजित करता है
  2. प्रत्येक टुकड़े के लिए एक धागा शुरू करता है
  3. थ्रेड में, बेतरतीब ढंग से सरणी फेरबदल करते हैं, जबकि स्टार्ट और एंडपॉइंट को ठीक रखते हैं
  4. यदि नई सरणी की दूरी कम है, तो इसे रखें
  5. 59 के बाद, मुख्य धागा परिणाम एकत्र करता है और इसे प्रिंट करता है

मार्ग में सबसे अच्छा सुधार खोजने के लिए विचार है, ताकि अन्य बॉट उनके तर्क के साथ विफल हो जाएं।

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
नोट: मैं बदल printlnकरने के लिए printअपने उत्पादन के अंत में न्यू लाइन से छुटकारा पाने के। अन्यथा यह दुर्घटनाग्रस्त हो जाता है।
जॉब

बदल दिया printlnकरने के लिए printऔर धागे की गिनती गतिशील बनाया है। यह अब 10 थ्रेड्स के साथ शुरू होता है ...
कॉमनग्यू

1

विभाजित और जीत + लालची बॉट

नोट: मैंने आपके कोड को Gameदेखा जिसके लिए 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++;

हालांकि, कोई catch(NumberFormatException)ब्लॉक नहीं है, इसलिए आपका कार्यक्रम संभावित रूप से दुर्घटनाग्रस्त हो जाएगा जब एक खिलाड़ी कार्यक्रम एक स्ट्रिंग को आउटपुट करता है (जैसा कि मेरे कार्यक्रम की mainविधि के अंत में दिखाया गया है )। मैं आपको इसे ठीक करने की सलाह देता हूं, क्योंकि कार्यक्रम अपवादों, स्टैक के निशान या पसंद को आउटपुट कर सकते हैं। अन्यथा, इससे पहले कि आप इसे चलाएं, मेरे कार्यक्रम में उस पंक्ति पर टिप्पणी करें।

विषय पर वापस जाएं

यह कार्यान्वयन (जावा में) अंक की सूची को 25 की संख्या में विभाजित करता है, सूची में बेतरतीब ढंग से स्थान दिया जाता है। फिर, यह प्रत्येक चंक में अंक के बीच का रास्ता छोटा करने के लिए थ्रेड बनाता है (इसलिए, "डिवाइड एंड कॉनकर")। मुख्य धागा दूसरों की निगरानी करता है और समय सीमा के भीतर सबसे छोटा समाधान प्रस्तुत करना सुनिश्चित करता है। यदि कोई धागा किसी समाधान के साथ या उसके बिना मर जाता है, तो यह एक अलग धागे को फिर से एक अलग चंक पर शुरू करता है।

प्रत्येक थ्रेड "लालची" एल्गोरिथ्म का उपयोग करता है, जो एक यादृच्छिक बिंदु पर शुरू होता है, निकटतम बिंदु पर जाता है, और तब तक दोहराता है जब तक कि सभी बिंदुओं को कवर नहीं किया जाता है (इसलिए, "लालची")।

टिप्पणियाँ

  • यह पूरे 1 मिनट के माध्यम से चलेगा (मैंने प्रोग्राम स्टार्टअप / शटडाउन और जेवीएम स्टार्टअप के लिए 3 सेकंड दिए - आपको कभी नहीं पता कि जेवीएम स्टार्टअप रूटीन आगे क्या हो सकता है ...)
  • यहां तक ​​कि अगर यह समाधान मिल गया है, यह खोज जारी रखेगा और 1 मिनट के बाद यह सबसे अच्छा समाधान प्रस्तुत करता है।
  • मुझे यकीन नहीं है कि यह कार्यान्वयन वास्तव में कोई अच्छा है। मैं इसे कोडन हालांकि कुछ मजेदार था :)
  • चूंकि बहुत सारी चीजें यादृच्छिक हैं, इसलिए यह समान इनपुट के लिए समान आउटपुट नहीं दे सकता है।

बस संकलन और java DivideAndConquer.classचलाने के लिए उपयोग करें।

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

क्या आप विश्वास कर सकते हैं? एसएक्स ने मुझे एक कैप्चा के लिए कहा जब मैंने इसे जमा किया! क्या यह आपको बॉट-मेड दिखता है? गंभीरता से?
डेंकेमेस

1
NFException धकेलने के लिए ठीक करें। अब यह सिर्फ कार्यक्रम को मारने के बजाय खिलाड़ी को मार देगा।
ज्योबिट्स

रिकॉर्ड के लिए, मुझे नहीं लगता कि यह आपके " अरे, मुझे आश्चर्य है कि अगर ... " लाइन पर वैसे भी क्रैश हो जाता । यह जांचता है कि क्या <200पार्स करने की कोशिश करने से पहले टोकन हैं । फिर भी इसके लिए जांच करना बेहतर है।
जियोबिट्स

@Geobits haha ​​ने महसूस नहीं किया कि
DankMemes

नोट: इसे संकलित करने के लिए, मुझे )19 लाइन पर जोड़ना होगा ; बदलने substrके लिए substringपर 38; विधि idxमें किसी चीज़ के लिए आरंभ करें run()
ज्योबिट्स
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.