एक बाढ़ पेंट एअर इंडिया बनाएँ


34

फ्लड पेंट के खेल में, पूरे बोर्ड को संभव के रूप में कुछ ही मोड़ में एक ही रंग होने के लिए खेल का लक्ष्य है।

खेल एक बोर्ड के साथ शुरू होता है जो कुछ इस तरह दिखता है:

3 3 5 4 1 3 4 1 5
5 1 3 4 1 1 5 2 1
6 5 2 3 4 3 3 4 3
4 4 4 5 5 5 4 1 4
6 2 5 3[3]1 1 6 6
5 5 1 2 5 2 6 6 3
6 1 1 5 3 6 2 3 6
1 2 2 4 5 3 5 1 2
3 6 6 1 5 1 3 2 4

वर्तमान में, बोर्ड के केंद्र में संख्या (एक रंग का प्रतिनिधित्व) 3 है। प्रत्येक मोड़ पर, केंद्र में वर्ग रंग बदल जाएगा, और एक ही रंग के सभी वर्ग जो क्षैतिज या लंबवत रूप से आगे बढ़ते हुए केंद्र से पहुंच रहे हैं ( यानी केंद्र के बाढ़ क्षेत्र में) इसके साथ रंग बदल जाएगा। इसलिए यदि केंद्र वर्ग 5 में रंग बदलता है:

3 3 5 4 1 3 4 1 5
5 1 3 4 1 1 5 2 1
6 5 2 3 4 3 3 4 3
4 4 4 5 5 5 4 1 4
6 2 5 5[5]1 1 6 6
5 5 1 2 5 2 6 6 3
6 1 1 5 3 6 2 3 6
1 2 2 4 5 3 5 1 2
3 6 6 1 5 1 3 2 4

फिर जो केंद्र 3 के बाईं ओर था वह भी रंग बदल देगा। अब केंद्र से एक के कुल सात 5 पहुंच रहे हैं, और इसलिए यदि हम रंग 4 में बदलते हैं:

3 3 5 4 1 3 4 1 5
5 1 3 4 1 1 5 2 1
6 5 2 3 4 3 3 4 3
4 4 4 4 4 4 4 1 4
6 2 4 4[4]1 1 6 6
5 5 1 2 4 2 6 6 3
6 1 1 5 3 6 2 3 6
1 2 2 4 5 3 5 1 2
3 6 6 1 5 1 3 2 4

चित्रित क्षेत्र फिर से नाटकीय रूप से आकार में बढ़ जाता है।

आपका कार्य एक ऐसा प्रोग्राम बनाना है जो 1 से 6 रंगों के 19 से 19 ग्रिड को इनपुट के रूप में लेगा, जो भी आप चुनते हैं:

4 5 1 1 2 2 1 6 2 6 3 4 2 3 2 3 1 6 3
4 2 6 3 4 4 5 6 4 4 5 3 3 3 3 5 4 3 4
2 3 5 2 2 5 5 1 2 6 2 6 6 2 1 6 6 1 2
4 6 5 5 5 5 4 1 6 6 3 2 6 4 2 6 3 6 6
1 6 4 4 4 4 6 4 2 5 5 3 2 2 4 1 5 2 5
1 6 2 1 5 1 6 4 4 1 5 1 3 4 5 2 3 4 1
3 3 5 3 2 2 2 4 2 1 6 6 6 6 1 4 5 2 5
1 6 1 3 2 4 1 3 3 4 6 5 1 5 5 3 4 3 3
4 4 1 5 5 1 4 6 3 3 4 5 5 6 1 6 2 6 4
1 4 2 5 6 5 5 3 2 5 5 5 3 6 1 4 4 6 6
4 6 6 2 6 6 2 4 2 6 1 5 6 2 3 3 4 3 6
6 1 3 6 3 5 5 3 6 1 3 4 4 5 1 2 6 4 3
2 6 1 3 2 4 2 6 1 1 5 2 6 6 6 6 3 3 3
3 4 5 4 6 6 3 3 4 1 1 6 4 5 1 3 4 1 2
4 2 6 4 1 5 3 6 4 3 4 5 4 2 1 1 4 1 1
4 2 4 1 5 2 2 3 6 6 6 5 2 5 4 5 4 5 1
5 6 2 3 4 6 5 4 1 3 2 3 2 1 3 6 2 2 4
6 5 4 1 3 2 2 1 1 1 6 1 2 6 2 5 6 4 5
5 1 1 4 2 6 2 5 6 1 3 3 4 1 6 1 2 1 2

और रंग का एक क्रम लौटाएं जिसे केंद्र वर्ग प्रत्येक मोड़ में बदल देगा, फिर से आपके चुनने के प्रारूप में:

263142421236425431645152623645465646213545631465

चाल के प्रत्येक अनुक्रम के अंत में, 19-बाय -19 ग्रिड में वर्गों को सभी समान रंग होना चाहिए।

आपका कार्यक्रम पूरी तरह से निर्धारक होना चाहिए; छद्म आयामी समाधान की अनुमति है, लेकिन कार्यक्रम को हर बार एक ही परीक्षण मामले के लिए एक ही आउटपुट उत्पन्न करना चाहिए।

जीतने वाला कार्यक्रम इस फ़ाइल में पाए गए सभी 100,000 परीक्षण मामलों को हल करने के लिए कम से कम कुल कदम उठाएगा (ज़िप्ड पाठ फ़ाइल, 14.25 एमबी)। यदि दो समाधान समान संख्या में कदम उठाते हैं (जैसे कि यदि वे दोनों इष्टतम रणनीति पाते हैं), तो छोटा कार्यक्रम जीत जाएगा।


BurntPizza ने परीक्षण परिणामों को सत्यापित करने के लिए जावा में एक कार्यक्रम लिखा है। इस कार्यक्रम का उपयोग करने के लिए, अपना सबमिशन चलाएं और आउटपुट को एक फ़ाइल में पाइप करें steps.txt। फिर, इस प्रोग्राम को steps.txtऔर floodtestउसी डायरेक्टरी में फाइल को रन करें । यदि आपकी प्रविष्टि मान्य है और सभी फ़ाइलों के लिए सही समाधान तैयार करती है, तो उसे सभी परीक्षण पास करने चाहिए और वापस आना चाहिएAll boards solved successfully.

import java.io.*;
import java.util.*;

public class PainterVerifier {

    public static void main(String[] args) throws FileNotFoundException {

        char[] board = new char[361];

        Scanner s = new Scanner(new File("steps.txt"));
        Scanner b = new Scanner(new File("floodtest"));

        int lineNum = 0;

        caseloop: while (b.hasNextLine()) {

            for (int l = 0; l < 19; l++) {
                String lineb = b.nextLine();
                if (lineb.isEmpty())
                    continue caseloop;
                System.arraycopy(lineb.toCharArray(), 0, board, l * 19, 19);
            }

            String line = s.nextLine();
            if (line.isEmpty())
                continue;
            char[] steps = line.toCharArray();

            Stack<Integer> nodes = new Stack<Integer>();

            for (char c : steps) {
                char targetColor = board[180];
                char replacementColor = c;

                nodes.push(180);

                while (!nodes.empty()) {
                    int n = nodes.pop();
                    if (n < 0 || n > 360)
                        continue;
                    if (board[n] == targetColor) {
                        board[n] = replacementColor;
                        if (n % 19 > 0)
                            nodes.push(n - 1);
                        if (n % 19 < 18)
                            nodes.push(n + 1);
                        if (n / 19 > 0)
                            nodes.push(n - 19);
                        if (n / 19 < 18)
                            nodes.push(n + 19);
                    }
                }
            }
            char center = board[180];
            for (char c : board)
                if (c != center) {
                    s.close();
                    b.close();

                    System.out.println("\nIncomplete board found!\n\tOn line " + lineNum + " of steps.txt");
                    System.exit(0);
                }

            if (lineNum % 5000 == 0)
                System.out.printf("Verification %d%c complete...\n", lineNum * 100 / 100000, '%');

            lineNum++;
        }
        s.close();
        b.close();
        System.out.println("All boards solved successfully.");
    }
}

इसके अलावा, एक स्कोरबोर्ड, क्योंकि परिणाम वास्तव में स्कोर से हल नहीं होते हैं और यहां यह वास्तव में बहुत मायने रखता है:

  1. 1,985,078 - स्मैक 42, जावा
  2. 2,075,452 - user1502040, सी
  3. 2,098,382 - बाघ, सी #
  4. 2,155,834 - कोडरताओ, सी #
  5. 2,201,995 - MrBackend, जावा
  6. 2,383,569 - कोडरताओ, सी #
  7. 2,384,020 - हर्जन, सी
  8. 2,403,189 - ओरिजिनिल, जावा
  9. 2,445,761 - हर्जन, सी
  10. 2,475,056 - जेरेमी सूची, हास्केल
  11. 2,480,714 - स्टीलटाइट, सी (2,395 बाइट्स)
  12. 2,480,714 - हर्जन, जावा (4,702 बाइट्स)
  13. 2,588,847 - बर्नटपज़ीज़ा, जावा (2,748 बाइट्स)
  14. 2,588,847 - गेरो 3, नोड.जेएस (4,641 बाइट्स)
  15. 2,979,145 - टेउन प्रैंक , डेल्फी एक्सई 3
  16. 4,780,841 - बर्नटपज़ीज़ा, जावा
  17. 10,800,000 - जो जेड, पायथन

2
अपने स्वयं के सबमिशन को देखते हुए आउटपुट में वास्तव में रिक्त स्थान नहीं होना चाहिए?
मार्टिन एंडर

5
यह ध्यान देने योग्य है कि परीक्षण इनपुट डेटा में संख्याओं के बीच रिक्त स्थान नहीं है।
अंडरस्कोर

3
आप अभी भी इसे लिख सकते हैं। यदि यह वर्तमान विजेता को रेखांकित करता है, तो मैं स्वीकृत उत्तर को बदल दूंगा।
जो जेड।

4
समय की कमी "आपको इसे चलाने और यहां वास्तविक परिणाम पोस्ट करने के लिए पर्याप्त तेज़ होना चाहिए"।
जो जेड।

2
@AlexanderRevo मुझे लगा कि मैंने फ़ाइल को स्थानांतरित नहीं किया है, लेकिन जाहिरा तौर पर लिंक के ऊपर और मेरे बिना ऐसा करने से बदल गया। यहाँ फिर से लिंक है।
जो जे।

जवाबों:


4

जावा - 1,985,078 कदम

https://github.com/smack42/ColorFill

एक और देर से प्रवेश। 1,985,078 चरणों वाली परिणाम फ़ाइल यहां पाई जा सकती है

कुछ पृष्ठभूमि जानकारी:

मुझे कुछ साल पहले इस चुनौती का पता चला, जब मैंने खेल फ्लड-इट का अपना क्लोन बनाना शुरू किया।

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

संपूर्ण डीएफएस एल्गोरिथ्म
तब मैंने एक एल्गोरिथ्म पर ध्यान केंद्रित किया जो हमेशा इष्टतम समाधान पाता है। मैंने अपनी संपूर्ण गहराई-पहली खोज रणनीति को अनुकूलित करने के लिए बहुत प्रयास किया। खोज को तेज करने के लिए, मैंने एक हैशमैप को शामिल किया, जो सभी अन्वेषण किए गए राज्यों को संग्रहीत करता है, ताकि खोज उन्हें फिर से खोज करने से बचा सके। जबकि यह एल्गोरिथ्म ठीक काम करता है और सभी 14x14 पहेलियों को जल्दी से हल करता है, यह बहुत अधिक मेमोरी का उपयोग करता है और इस कोड चुनौती में 19x19 पहेली के साथ बहुत धीरे चलता है।

पुचर्ट ए * एल्गोरिथ्म
कुछ महीने पहले मुझे एरोन और साइमन पुचर्ट द्वारा फ्लड-इट सॉल्वर देखने के लिए संपर्क किया गया था । उस कार्यक्रम में एक स्वीकार्य हैरिस्टिक के साथ ए * -टाइप एल्गोरिथ्म का उपयोग किया जाता है (टाइगरो के विपरीत) और जंप-प्वाइंट सर्च के समान छंटाई करता है। मैंने जल्दी से देखा कि यह कार्यक्रम बहुत तेज है और इष्टतम समाधान ढूंढता है !

बेशक, मुझे इस महान एल्गोरिथ्म को फिर से लागू करना था और इसे अपने कार्यक्रम में जोड़ा। मैंने पुचर्ट भाइयों द्वारा मूल सी ++ कार्यक्रम के रूप में तेजी से चलाने के लिए अपने जावा प्रोग्राम को अनुकूलित करने का प्रयास किया। तब मैंने इस चुनौती के 100,000 परीक्षण मामलों में एक प्रयास करने का फैसला किया। मेरी मशीन पर, पुचर्ट ए * एल्गोरिथ्म के मेरे कार्यान्वयन का उपयोग करके 1,985,078 चरणों को खोजने के लिए कार्यक्रम 120 घंटे से अधिक समय तक चला

यह इस चुनौती का सबसे अच्छा संभव समाधान है, जब तक कि कार्यक्रम में कुछ कीड़े न हों जो उप-इष्टतम समाधानों में परिणत होंगे। किसी भी प्रतिक्रिया का स्वागत है!

संपादित करें: कोड के संबंधित भागों को यहां जोड़ा गया है:

वर्ग AStarPuchertStrategy

/**
 * a specific strategy for the AStar (A*) solver.
 * <p>
 * the idea is taken from the program "floodit" by Aaron and Simon Puchert,
 * which can be found at <a>https://github.com/aaronpuchert/floodit</a>
 */
public class AStarPuchertStrategy implements AStarStrategy {

    private final Board board;
    private final ColorAreaSet visited;
    private ColorAreaSet current, next;
    private final short[] numCaNotFilledInitial;
    private final short[] numCaNotFilled;

    public AStarPuchertStrategy(final Board board) {
        this.board = board;
        this.visited = new ColorAreaSet(board);
        this.current = new ColorAreaSet(board);
        this.next = new ColorAreaSet(board);
        this.numCaNotFilledInitial = new short[board.getNumColors()];
        for (final ColorArea ca : board.getColorAreasArray()) {
            ++this.numCaNotFilledInitial[ca.getColor()];
        }
        this.numCaNotFilled = new short[board.getNumColors()];
    }

    /* (non-Javadoc)
     * @see colorfill.solver.AStarStrategy#setEstimatedCost(colorfill.solver.AStarNode)
     */
    @Override
    public void setEstimatedCost(final AStarNode node) {

        // quote from floodit.cpp: int State::computeValuation()
        // (in branch "performance")
        //
        // We compute an admissible heuristic recursively: If there are no nodes
        // left, return 0. Furthermore, if a color can be eliminated in one move
        // from the current position, that move is an optimal move and we can
        // simply use it. Otherwise, all moves fill a subset of the neighbors of
        // the filled nodes. Thus, filling that layer gets us at least one step
        // closer to the end.

        node.copyFloodedTo(this.visited);
        System.arraycopy(this.numCaNotFilledInitial, 0, this.numCaNotFilled, 0, this.numCaNotFilledInitial.length);
        {
            final ColorAreaSet.FastIteratorColorAreaId iter = this.visited.fastIteratorColorAreaId();
            int nextId;
            while ((nextId = iter.nextOrNegative()) >= 0) {
                --this.numCaNotFilled[this.board.getColor4Id(nextId)];
            }
        }

        // visit the first layer of neighbors, which is never empty, i.e. the puzzle is not solved yet
        node.copyNeighborsTo(this.current);
        this.visited.addAll(this.current);
        int completedColors = 0;
        {
            final ColorAreaSet.FastIteratorColorAreaId iter = this.current.fastIteratorColorAreaId();
            int nextId;
            while ((nextId = iter.nextOrNegative()) >= 0) {
                final byte nextColor = this.board.getColor4Id(nextId);
                if (--this.numCaNotFilled[nextColor] == 0) {
                    completedColors |= 1 << nextColor;
                }
            }
        }
        int distance = 1;

        while(!this.current.isEmpty()) {
            this.next.clear();
            final ColorAreaSet.FastIteratorColorAreaId iter = this.current.fastIteratorColorAreaId();
            int thisCaId;
            if (0 != completedColors) {
                // We can eliminate colors. Do just that.
                // We also combine all these elimination moves.
                distance += Integer.bitCount(completedColors);
                final int prevCompletedColors = completedColors;
                completedColors = 0;
                while ((thisCaId = iter.nextOrNegative()) >= 0) {
                    final ColorArea thisCa = this.board.getColorArea4Id(thisCaId);
                    if ((prevCompletedColors & (1 << thisCa.getColor())) != 0) {
                        // completed color
                        // expandNode()
                        for (final int nextCaId : thisCa.getNeighborsIdArray()) {
                            if (!this.visited.contains(nextCaId)) {
                                this.visited.add(nextCaId);
                                this.next.add(nextCaId);
                                final byte nextColor = this.board.getColor4Id(nextCaId);
                                if (--this.numCaNotFilled[nextColor] == 0) {
                                    completedColors |= 1 << nextColor;
                                }
                            }
                        }
                    } else {
                        // non-completed color
                        // move node to next layer
                        this.next.add(thisCaId);
                    }
                }
            } else {
                // Nothing found, do the color-blind pseudo-move
                // Expand current layer of nodes.
                ++distance;
                while ((thisCaId = iter.nextOrNegative()) >= 0) {
                    final ColorArea thisCa = this.board.getColorArea4Id(thisCaId);
                    // expandNode()
                    for (final int nextCaId : thisCa.getNeighborsIdArray()) {
                        if (!this.visited.contains(nextCaId)) {
                            this.visited.add(nextCaId);
                            this.next.add(nextCaId);
                            final byte nextColor = this.board.getColor4Id(nextCaId);
                            if (--this.numCaNotFilled[nextColor] == 0) {
                                completedColors |= 1 << nextColor;
                            }
                        }
                    }
                }
            }

            // Move the next layer into the current.
            final ColorAreaSet tmp = this.current;
            this.current = this.next;
            this.next = tmp;
        }
        node.setEstimatedCost(node.getSolutionSize() + distance);
    }

}

वर्ग का हिस्सा AStarSolver

private void executeInternalPuchert(final ColorArea startCa) throws InterruptedException {
    final Queue<AStarNode> open = new PriorityQueue<AStarNode>(AStarNode.strongerComparator());
    open.offer(new AStarNode(this.board, startCa));
    AStarNode recycleNode = null;
    while (open.size() > 0) {
        if (Thread.interrupted()) { throw new InterruptedException(); }
        final AStarNode currentNode = open.poll();
        if (currentNode.isSolved()) {
            this.addSolution(currentNode.getSolution());
            return;
        } else {
            // play all possible colors
            int nextColors = currentNode.getNeighborColors(this.board);
            while (0 != nextColors) {
                final int l1b = nextColors & -nextColors; // Integer.lowestOneBit()
                final int clz = Integer.numberOfLeadingZeros(l1b); // hopefully an intrinsic function using instruction BSR / LZCNT / CLZ
                nextColors ^= l1b; // clear lowest one bit
                final byte color = (byte)(31 - clz);
                final AStarNode nextNode = currentNode.copyAndPlay(color, recycleNode, this.board);
                if (null != nextNode) {
                    recycleNode = null;
                    this.strategy.setEstimatedCost(nextNode);
                    open.offer(nextNode);
                }
            }
        }
        recycleNode = currentNode;
    }
}

वर्ग का हिस्सा AStarNode

/**
 * check if this color can be played. (avoid duplicate moves)
 * the idea is taken from the program "floodit" by Aaron and Simon Puchert,
 * which can be found at <a>https://github.com/aaronpuchert/floodit</a>
 * @param nextColor
 * @return
 */
private boolean canPlay(final byte nextColor, final List<ColorArea> nextColorNeighbors) {
    final byte currColor = this.solution[this.solutionSize];
    // did the previous move add any new "nextColor" neighbors?
    boolean newNext = false;
next:   for (final ColorArea nextColorNeighbor : nextColorNeighbors) {
        for (final ColorArea prevNeighbor : nextColorNeighbor.getNeighborsArray()) {
            if ((prevNeighbor.getColor() != currColor) && this.flooded.contains(prevNeighbor)) {
                continue next;
            }
        }
        newNext = true;
        break next;
    }
    if (!newNext) {
        if (nextColor < currColor) {
            return false;
        } else {
            // should nextColor have been played before currColor?
            for (final ColorArea nextColorNeighbor : nextColorNeighbors) {
                for (final ColorArea prevNeighbor : nextColorNeighbor.getNeighborsArray()) {
                    if ((prevNeighbor.getColor() == currColor) && !this.flooded.contains(prevNeighbor)) {
                        return false;
                    }
                }
            }
            return true;
        }
    } else {
        return true;
    }
}

/**
 * try to re-use the given node or create a new one
 * and then play the given color in the result node.
 * @param nextColor
 * @param recycleNode
 * @return
 */
public AStarNode copyAndPlay(final byte nextColor, final AStarNode recycleNode, final Board board) {
    final List<ColorArea> nextColorNeighbors = new ArrayList<ColorArea>(128);  // constant, arbitrary initial capacity
    final ColorAreaSet.FastIteratorColorAreaId iter = this.neighbors.fastIteratorColorAreaId();
    int nextId;
    while ((nextId = iter.nextOrNegative()) >= 0) {
        final ColorArea nextColorNeighbor = board.getColorArea4Id(nextId);
        if (nextColorNeighbor.getColor() == nextColor) {
            nextColorNeighbors.add(nextColorNeighbor);
        }
    }
    if (!this.canPlay(nextColor, nextColorNeighbors)) {
        return null;
    } else {
        final AStarNode result;
        if (null == recycleNode) {
            result = new AStarNode(this);
        } else {
            // copy - compare copy constructor
            result = recycleNode;
            result.flooded.copyFrom(this.flooded);
            result.neighbors.copyFrom(this.neighbors);
            System.arraycopy(this.solution, 0, result.solution, 0, this.solutionSize + 1);
            result.solutionSize = this.solutionSize;
            //result.estimatedCost = this.estimatedCost;  // not necessary to copy
        }
        // play - compare method play()
        for (final ColorArea nextColorNeighbor : nextColorNeighbors) {
            result.flooded.add(nextColorNeighbor);
            result.neighbors.addAll(nextColorNeighbor.getNeighborsIdArray());
        }
        result.neighbors.removeAll(result.flooded);
        result.solution[++result.solutionSize] = nextColor;
        return result;
    }
}

2
PPCG में आपका स्वागत है! क्या आप अपने उत्तर में सॉल्वर के लिए संबंधित कोड शामिल कर सकते हैं, ताकि यह स्व-निहित हो, क्या आपका गीथब रेपो कभी नीचे जाना चाहिए या नीचे जाना चाहिए?
मार्टिन एंडर

यहां कोड के सबसे प्रासंगिक हिस्सों को जोड़ा गया: "पुचर्ट ए * एल्गोरिथ्म" का मेरा कार्यान्वयन। (यह कोड अंश स्व-निहित नहीं है और इसे संकलित नहीं किया जा सकता है)
smack42

मुझे खुशी है कि किसी को इसके लिए एक सही / इष्टतम समाधान मिला। लेकिन दूसरी तरफ, इसका मतलब है कि अधिक प्रतियोगिता / नए उत्तर नहीं होंगे।
tigrou

15

सी # - 2,098,382 कदम

मैं कई चीजों की कोशिश करता हूं, उनमें से ज्यादातर विफल हो जाते हैं और अभी हाल ही में काम नहीं किया। मुझे उत्तर पोस्ट करने के लिए कुछ दिलचस्प मिला।

निश्चित रूप से इसे और बेहतर बनाने के तरीके हैं। मुझे लगता है कि 2M चरणों के तहत जाना संभव हो सकता है।

7 hoursपरिणाम उत्पन्न करने में लगभग लग गया । यहां सभी समाधानों के साथ एक txt फ़ाइल है, अगर कोई उन्हें जाँचना चाहता है: results.zip

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;

namespace FloodPaintAI
{
    class Node
    {   
        public byte Value;             //1-6
        public int Index;              //unique identifier, used for easily deepcopying the graph
        public List<Node> Neighbours;  
        public List<Tuple<int, int>> NeighboursPositions; //used by BuildGraph() 

        public int Depth;    //used by GetSumDistances() 
        public bool Checked; // 

        public Node(byte value, int index)
        {
            Value = value;      
            Index = index;          
        }

        public Node(Node node)
        {           
            Value = node.Value; 
            Index = node.Index;                     
        }
    }

    class Board
    {
        private const int SIZE = 19;
        private const int STARTPOSITION = 9;

        public Node Root;         //root of graph. each node is a set of contiguous, same color square
        public List<Node> Nodes;  //all nodes in the graph, used for deep copying


        public int EstimatedCost; //estimated cost, used by A* Pathfinding
        public List<byte> Solution;

        public Board(StreamReader input)
        {                   
            byte[,] board = new byte[SIZE, SIZE];
            for(int j = 0 ; j < SIZE ; j++)
            {
                string line = input.ReadLine();
                for(int i = 0 ; i < SIZE ; i++)         
                {                                       
                    board[j, i] = byte.Parse(line[i].ToString());
                }               
            }
            Solution = new List<byte>();
            BuildGraph(board);  
        }

        public Board(Board boardToCopy)
        {               
            //copy the graph            
            Nodes = new List<Node>(boardToCopy.Nodes.Count);
            foreach(Node nodeToCopy in boardToCopy.Nodes)
            {
                Node node = new Node(nodeToCopy);
                Nodes.Add(node);
            }

            //copy "Neighbours" property
            for(int i = 0 ; i < boardToCopy.Nodes.Count ; i++)
            {
                Node node = Nodes[i];
                Node nodeToCopy = boardToCopy.Nodes[i];

                node.Neighbours = new List<Node>(nodeToCopy.Neighbours.Count);
                foreach(Node neighbour in nodeToCopy.Neighbours)
                {
                    node.Neighbours.Add(Nodes[neighbour.Index]);
                }
            }

            Root = Nodes[boardToCopy.Root.Index];
            EstimatedCost = boardToCopy.EstimatedCost;          
            Solution = new List<byte>(boardToCopy.Solution);            
        }

        private void BuildGraph(byte[,] board)
        {                       
            int[,] nodeIndexes = new int[SIZE, SIZE];
            Nodes = new List<Node>();

            //check how much sets we have (1st pass)
            for(int j = 0 ; j < SIZE ; j++)
            {
                for(int i = 0 ; i < SIZE ; i++)         
                {               
                    if(nodeIndexes[j, i] == 0) //not already visited                    
                    {
                        Node newNode = new Node(board[j, i], Nodes.Count);                      
                        newNode.NeighboursPositions = new List<Tuple<int, int>>();
                        Nodes.Add(newNode);

                        BuildGraphFloodFill(board, nodeIndexes, newNode, i, j, board[j, i]);
                    }
                }       
            }

            //set neighbours and root (2nd pass)
            foreach(Node node in Nodes)
            {
                node.Neighbours = new List<Node>();
                node.Neighbours.AddRange(node.NeighboursPositions.Select(x => nodeIndexes[x.Item2, x.Item1]).Distinct().Select(x => Nodes[x - 1]));
                node.NeighboursPositions = null;                
            }
            Root = Nodes[nodeIndexes[STARTPOSITION, STARTPOSITION] - 1];            
        }

        private void BuildGraphFloodFill(byte[,] board, int[,] nodeIndexes, Node node, int startx, int starty, byte floodvalue)
        {
            Queue<Tuple<int, int>> queue = new Queue<Tuple<int, int>>();
            queue.Enqueue(new Tuple<int, int>(startx, starty));

            while(queue.Count > 0)
            {
                Tuple<int, int> position = queue.Dequeue();
                int x = position.Item1;
                int y = position.Item2;

                if(x >= 0 && x < SIZE && y >= 0 && y < SIZE)
                {
                    if(nodeIndexes[y, x] == 0 && board[y, x] == floodvalue)
                    {
                        nodeIndexes[y, x] = node.Index + 1;

                        queue.Enqueue(new Tuple<int, int>(x + 1, y));
                        queue.Enqueue(new Tuple<int, int>(x - 1, y));
                        queue.Enqueue(new Tuple<int, int>(x, y + 1));
                        queue.Enqueue(new Tuple<int, int>(x, y - 1));                                           
                    }               
                    if(board[y, x] != floodvalue)
                        node.NeighboursPositions.Add(position);                         
                }       
            }
        }

        public int GetEstimatedCost()
        {       
            Board current = this;

            //copy current board and play the best color until the end.
            //number of moves required to go the end is the heuristic
            //estimated cost = current cost + heuristic
            while(!current.IsSolved())
            {
                int minSumDistance = int.MaxValue;
                Board minBoard = null;

                //find color which give the minimum sum of distance from root to each other node
                foreach(byte i in current.Root.Neighbours.Select(x => x.Value).Distinct())
                {
                    Board copy = new Board(current);
                    copy.Play(i);                   

                    int distance = copy.GetSumDistances();                  

                    if(distance < minSumDistance)
                    {
                        minSumDistance = distance;
                        minBoard = copy;
                    }
                }
                current = minBoard;
            }           
            return current.Solution.Count;
        }

        public int GetSumDistances()
        {
            //get sum of distances from root to each other node, using BFS
            int sumDistances = 0;           

            //reset marker
            foreach(Node n in Nodes)
            {
                n.Checked = false;                                  
            }

            Queue<Node> queue = new Queue<Node>();
            Root.Checked = true;
            Root.Depth = 0; 
            queue.Enqueue(Root);

            while(queue.Count > 0)
            {
                Node current = queue.Dequeue();                             
                foreach(Node n in current.Neighbours)
                {
                    if(!n.Checked)          
                    {                                   
                        n.Checked = true;                                               
                        n.Depth = current.Depth + 1;
                        sumDistances += n.Depth;            
                        queue.Enqueue(n);   
                    }               
                }
            }
            return sumDistances;
        }       

        public void Play(byte value)            
        {
            //merge root node with other neighbours nodes, if color is matching
            Root.Value = value;
            List<Node> neighboursToRemove = Root.Neighbours.Where(x => x.Value == value).ToList();
            List<Node> neighboursToAdd = neighboursToRemove.SelectMany(x => x.Neighbours).Except((new Node[] { Root }).Concat(Root.Neighbours)).ToList();

            foreach(Node n in neighboursToRemove)
            {
                foreach(Node m in n.Neighbours)
                {
                    m.Neighbours.Remove(n);
                }
                Nodes.Remove(n);
            }   

            foreach(Node n in neighboursToAdd)
            {
                Root.Neighbours.Add(n);         
                n.Neighbours.Add(Root); 
            }           

            //re-synchronize node index
            for(int i = 0 ; i < Nodes.Count ; i++)
            {
                Nodes[i].Index = i;
            }           
            Solution.Add(value);
        }

        public bool IsSolved()
        {           
            //return Nodes.Count == 1;
            return Root.Neighbours.Count == 0;  
        }           
    }


    class Program
    {       
        public static List<byte> Solve(Board input)
        {
            //A* Pathfinding            
            LinkedList<Board> open = new LinkedList<Board>();       
            input.EstimatedCost = input.GetEstimatedCost();
            open.AddLast(input);            

            while(open.Count > 0)
            {                       
                Board current = open.First.Value;
                open.RemoveFirst();

                if(current.IsSolved())
                {
                    return current.Solution;                
                }
                else
                {
                    //play all neighbours nodes colors
                    foreach(byte i in current.Root.Neighbours.Select(x => x.Value).Distinct())
                    {                       
                        Board newBoard = new Board(current);
                        newBoard.Play(i);           
                        newBoard.EstimatedCost = newBoard.GetEstimatedCost();   

                        //insert board to open list
                        bool inserted = false;
                        for(LinkedListNode<Board> node = open.First ; node != null ; node = node.Next)
                        {                               
                            if(node.Value.EstimatedCost > newBoard.EstimatedCost)
                            {
                                open.AddBefore(node, newBoard);
                                inserted = true;
                                break;
                            }
                        }       
                        if(!inserted)
                            open.AddLast(newBoard);                                                 
                    }   
                }   
            }
            throw new Exception(); //no solution found, impossible
        }   

        public static void Main(string[] args)
        {                   
            using (StreamReader sr = new StreamReader("floodtest"))
            {   
                while(!sr.EndOfStream)
                {                               
                    List<Board> boards = new List<Board>();
                    while(!sr.EndOfStream && boards.Count < 100)
                    {
                        Board board = new Board(sr);                        
                        sr.ReadLine(); //skip empty line
                        boards.Add(board);
                    }                                           
                    List<byte>[] solutions = new List<byte>[boards.Count];                                          
                    Parallel.For(0, boards.Count, i => 
                    {                               
                        solutions[i] = Solve(boards[i]); 
                    });                                         
                    foreach(List<byte> solution in solutions)
                    {
                        Console.WriteLine(string.Join(string.Empty, solution));                                             
                    }       
                }               
            }
        }
    }
}

यह कैसे काम करता है इसके बारे में अधिक जानकारी:

यह ए * पाथफाइंडिंग एल्गोरिथ्म का उपयोग करता है।

जो अच्छा है उसे पाना मुश्किल है heuristic। यदि heuristicयह लागत को कम करता है, तो यह लगभग दिक्जस्ट्रा एल्गोरिथम की तरह प्रदर्शन करेगा और 6 रंगों के साथ 19x19 बोर्ड की जटिलता के कारण यह हमेशा के लिए चलेगा। यदि यह लागत को कम कर देता है तो यह जल्दी से एक समाधान में परिवर्तित हो जाएगा, लेकिन अच्छे लोगों को बिल्कुल नहीं देगा (26 चाल की तरह कुछ संभव था)। सही ढूँढना जो heuristicसमाधान तक पहुंचने के लिए सटीक शेष राशि देता है वह सबसे अच्छा होगा (यह तेज़ होगा और सर्वोत्तम संभव समाधान देगा)। यह (जब तक मैं गलत हूं) असंभव है। यह वास्तव में बोर्ड को पहले हल करने की आवश्यकता है, जबकि यह वही है जो आप वास्तव में करने की कोशिश कर रहे हैं (चिकन और अंडे की समस्या)

मैंने कई चीजों की कोशिश की, यहाँ इस बात के लिए काम किया गया है heuristic:

  • मैं मूल्यांकन करने के लिए वर्तमान बोर्ड का एक ग्राफ बनाता हूं । प्रत्येक node, एक ही रंग के चौकोर, एक ही रंग के वर्गों का प्रतिनिधित्व करता है। इसका उपयोग करते हुए graph, मैं आसानी से केंद्र से किसी भी अन्य नोड के लिए सटीक न्यूनतम दूरी की गणना कर सकता हूं। उदाहरण के लिए केंद्र से शीर्ष बाईं ओर की दूरी 10 होगी, क्योंकि न्यूनतम 10 रंग उन्हें अलग करते हैं।
  • गणना के लिए heuristic: मैं अंत तक वर्तमान बोर्ड खेलता हूं। प्रत्येक चरण के लिए, मैं उस रंग को चुनता हूं जो जड़ से अन्य सभी नोड्स तक की दूरी को कम कर देगा।
  • उस छोर तक पहुंचने के लिए आवश्यक चालों की संख्या है heuristic

  • Estimated cost(ए * द्वारा प्रयुक्त) = moves so far+heuristic

यह बिल्कुल सही नहीं है क्योंकि यह लागत को थोड़ा कम कर देता है (इस प्रकार गैर इष्टतम समाधान पाया जाता है)। वैसे भी यह अच्छे परिणाम की गणना और देने के लिए तेज़ है।

मैं सभी कार्यों को करने के लिए ग्राफ का उपयोग करके भारी गति सुधार प्राप्त करने में सक्षम था। भीख माँगने पर मेरे पास एक 2-dimensionसरणी थी। मैं इसे बाढ़ और जरूरत पड़ने पर पुनर्गणना ग्राफ (जैसे: अनुमान की गणना करने के लिए)। अब सब कुछ ग्राफ़ का उपयोग करके किया जाता है, जिसकी गणना केवल शुरुआत में की जाती है। चरणों का अनुकरण करने के लिए, बाढ़ भरण की आवश्यकता नहीं है, मैं इसके बजाय नोड्स को मर्ज करता हूं। यह बहुत तेज है।


2
कृपया code blocksपाठ पर जोर देने के लिए उपयोग न करें । हमारे पास इसके लिए इटैलिक और बोल्ड है।
निधि मोनिका का मुकदमा

10

पायथन - 10,800,000 कदम

अंतिम स्थान के संदर्भ समाधान के रूप में, इस क्रम पर विचार करें:

print "123456" * 18

सभी रंगों के nसमय के बीच साइकिल चलाने का मतलब है कि हर वर्ग की nदूरी पर केंद्र वर्ग के समान रंग की गारंटी होगी। प्रत्येक वर्ग केंद्र से अधिकतम 18 कदम की दूरी पर है, इसलिए 18 चक्र सभी वर्गों को एक ही रंग होने की गारंटी देंगे। सबसे अधिक संभावना है कि यह उससे कम में खत्म हो जाएगा, लेकिन सभी वर्गों के समान रंग के होते ही कार्यक्रम को रोकना आवश्यक नहीं है; ऐसा करना ज्यादा फायदेमंद है। यह निरंतर प्रक्रिया प्रति परीक्षण मामले में 108 कदम है, कुल 10,800,000 के लिए।


जानवर बल विधि, गंभीरता से ...? जो, मैंने सोचा कि आपको बेहतर जानने के लिए थोड़ा और अनुभव था, दोस्त?
1

2
यह एक गंभीर प्रविष्टि के रूप में नहीं है। ध्यान दें कि मैंने इसे विशेष रूप से अंतिम स्थान पर कैच-ऑल के रूप में कार्य करने के लिए एक समाधान के रूप में रखा है । किसी भी गंभीर प्रविष्टि का स्कोर इस से बहुत कम होगा।
जो Z.

वहाँ रिक्त स्थान नहीं होना चाहिए? के रूप में 1 2 3 4 5 6 ...के बजाय अपने वर्तमान समाधान जो देता है 123456...
user80551

1
कोड गोल्फ के लिए इष्टतम एल्गोरिदम होगा (किसी अन्य भाषा में हालांकि "प्रिंट" बहुत अधिक वर्ण है)।
क्रंचर

1
मैं यह भी नहीं सोचता कि 18 चरणों का सबसे खराब मामला भी संभव है । लेकिन निश्चित रूप से हम जानते हैं कि इससे बुरा कोई मामला नहीं है, इसलिए यह निश्चित रूप से काम करता है :)
Cruncher

8

जावा - 2,480,714 चरण

मैंने पहले थोड़ी गलती की (मैंने एक महत्वपूर्ण वाक्य को लूप के बजाय लूप से पहले रखा:

import java.io.*;

public class HerjanPaintAI {

    BufferedReader r;
    String[] map = new String[19];
    char[][] colors = new char[19][19];
    boolean[][] reached = new boolean[19][19], checked = new boolean[19][19];
    int[] colorCounter = new int[6];
    String answer = "";
    int mapCount = 0, moveCount = 0;

    public HerjanPaintAI(){
        nextMap();

        while(true){

            int bestMove = nextRound();
            answer += bestMove;
            char t = Character.forDigit(bestMove, 10);
            for(int x = 0; x < 19; x++){
                for(int y = 0; y < 19; y++){
                    if(reached[x][y]){
                        colors[x][y] = t;
                    }else if(checked[x][y]){
                        if(colors[x][y] == t){
                            reached[x][y] = true;
                        }
                    }
                }
            }

            boolean gameOver = true;
            for(int x = 0; x < 19; x++){
                for(int y = 0; y < 19; y++){
                    if(!reached[x][y]){
                        gameOver = false;
                        break;
                    }
                }
            }

            for(int x = 0; x < 19; x++){
                for(int y = 0; y < 19; y++){
                    checked[x][y] = false;
                }
            }
            for(int i = 0; i < 6; i++)
                colorCounter[i] = 0;

            if(gameOver)
                nextMap();
        }
    }

    int nextRound(){
        for(int x = 0; x < 19; x++){
            for(int y = 0; y < 19; y++){
                if(reached[x][y]){//check what numbers are next to the reached numbers...
                    check(x, y);
                }
            }
        }

        int[] totalColorCount = new int[6];
        for(int x = 0; x < 19; x++){
            for(int y = 0; y < 19; y++){
                totalColorCount[Character.getNumericValue(colors[x][y])-1]++;
            }
        }

        for(int i = 0; i < 6; i++){
            if(totalColorCount[i] != 0 && totalColorCount[i] == colorCounter[i]){//all of this color can be reached
                return i+1;
            }
        }

        int index = -1, number = 0;
        for(int i = 0; i < 6; i++){
            if(colorCounter[i] > number){
                index = i;
                number = colorCounter[i];
            }
        }

        return index+1;
    }

    void check(int x, int y){
        if(x<18)
            handle(x+1, y, x, y);
        if(x>0)
            handle(x-1, y, x, y);
        if(y<18)
            handle(x, y+1, x, y);
        if(y>0)
            handle(x, y-1, x, y);
    }

    void handle(int x2, int y2, int x, int y){
        if(!reached[x2][y2] && !checked[x2][y2]){
            checked[x2][y2] = true;
            if(colors[x2][y2] == colors[x][y]){
                reached[x2][y2] = true;
                check(x2, y2);
            }else{
                colorCounter[Character.getNumericValue(colors[x2][y2])-1]++;
                checkAround(x2, y2);
            }
        }
    }

    void checkAround(int x2, int y2){
        if(x2<18)
            handleAround(x2+1, y2, x2, y2);
        if(x2>0)
            handleAround(x2-1, y2, x2, y2);
        if(y2<18)
            handleAround(x2, y2+1, x2, y2);
        if(y2>0)
            handleAround(x2, y2-1, x2, y2);
    }

    void handleAround(int x2, int y2, int x, int y){
        if(!reached[x2][y2] && !checked[x2][y2]){
            if(colors[x2][y2] == colors[x][y]){
                checked[x2][y2] = true;
                colorCounter[Character.getNumericValue(colors[x2][y2])-1]++;
                checkAround(x2, y2);
            }
        }
    }

    void nextMap(){
        moveCount += answer.length();
        System.out.println(answer);
        answer = "";

        for(int x = 0; x < 19; x++){
            for(int y = 0; y < 19; y++){
                reached[x][y] = false;
            }
        }

        reached[9][9] = true;

        try {
            if(r == null)
                r = new BufferedReader(new FileReader("floodtest"));

            for(int i = 0; i < 19; i++){
                map[i] = r.readLine();
            }
            r.readLine();//empty line

            if(map[0] == null){
                System.out.println("Maps solved: " + mapCount + " Steps: " + moveCount);
                r.close();
                System.exit(0);
            }
        } catch (Exception e) {e.printStackTrace();}

        mapCount++;

        for(int x = 0; x < 19; x++){
            colors[x] = map[x].toCharArray();
        }
    }

    public static void main(String[] a){
        new HerjanPaintAI();
    }
}

इसे चलाने में कितना समय लगा?
एलेक्जेंडर-ब्रेट

@ अलियाशा मेरा पीसी आधा मिनट भी नहीं हुआ
हर्जन

अच्छी तरह से बकवास। मेरा आधे घंटे से चल रहा है ...
अलेक्जेंडर-ब्रेट

गोल्फ की आवश्यकता नहीं है, वैसे।
जो जेड।

1
@ m.buettner शैतान की बात करो, किसी ने इस समाधान को बाँध दिया (और छोटा कोड था) आपके कहने के तीन घंटे बाद।
जो जेड।

5

सी - 2,075,452

मुझे पता है कि मैं पार्टी में बहुत देर से आता हूं, लेकिन मैंने इस चुनौती को देखा और जाना चाहता था।

#include <assert.h>
#include <math.h>
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>

uint64_t rand_state;

uint64_t rand_u64(void) {
    return (rand_state = rand_state * 6364136223846793005ULL + 1442695040888963407ULL);
}

uint64_t better_rand_u64(void) {
    uint64_t r = rand_u64();
    r ^= ((r >> 32) >> (r >> 60));
    return r + 1442695040888963407ULL;
}

uint32_t rand_u32(void) {return rand_u64() >> 32;}

float normal(float mu, float sigma) {
    uint64_t t = 0;
    for (int i = 0; i < 6; i++) {
        uint64_t r = rand_u64();
        uint32_t a = r;
        uint32_t b = r >> 32;
        t += a;
        t += b;
    }
    return ((float)t / (float)UINT32_MAX - 6) * sigma + mu;
}

typedef struct {
    uint8_t x;
    uint8_t y;
} Position;

#define ncolors 6
#define len 19
#define cells (len * len)
#define max_steps (len * (ncolors - 1))
#define center_x 9
#define center_y 9
#define center ((Position){center_x, center_y})

uint64_t zobrist_table[len][len];

void init_zobrist() {
    for (int y = 0; y < len; y++) {
        for (int x = 0; x < len; x++) {
            zobrist_table[y][x] = better_rand_u64();
        }
    }
}

typedef struct {
    uint64_t hash;
    uint8_t grid[len][len];
    bool interior[len][len];
    int boundary_size;
    Position boundary[cells];
} Grid;


void transition(Grid* grid, uint8_t color, int* surrounding_counts) {
    int i = 0;
    while (i < grid->boundary_size) {
        Position p = grid->boundary[i];
        uint8_t x = p.x;
        uint8_t y = p.y;
        bool still_boundary = false;
        for (int dx = -1; dx <= 1; dx++) {
            for (int dy = -1; dy <= 1; dy++) {
                if (!(dx == 0 || dy == 0)) {
                    continue;
                }
                int8_t x1 = x + dx;
                if (!(0 <= x1 && x1 < len)) {
                    continue;
                }
                int8_t y1 = y + dy;
                if (!(0 <= y1 && y1 < len)) {
                    continue;
                }
                if (grid->interior[y1][x1]) {
                    continue;
                }
                uint8_t color1 = grid->grid[y1][x1];
                if (color1 == color) {
                    grid->boundary[grid->boundary_size++] = (Position){x1, y1};
                    grid->interior[y1][x1] = true;
                    grid->hash ^= zobrist_table[y1][x1];
                } else {
                    surrounding_counts[color1]++;
                    still_boundary = true;
                }
            }
        }
        if (still_boundary) {
            i += 1;
        } else {
            grid->boundary[i] = grid->boundary[--grid->boundary_size]; 
        }
    }
}

void reset_grid(Grid* grid, int* surrounding_counts) {
    grid->hash = 0;
    memset(surrounding_counts, 0, ncolors * sizeof(int)); 
    memset(&grid->interior, 0, sizeof(grid->interior));
    grid->interior[center_y][center_x] = true;
    grid->boundary_size = 0;
    grid->boundary[grid->boundary_size++] = center; 
    transition(grid, grid->grid[center_y][center_x], surrounding_counts);
}

bool load_grid(FILE* fp, Grid* grid) {
    memset(grid, 0, sizeof(*grid));
    char buf[19 + 2];
    size_t row = 0;
    while ((fgets(buf, sizeof(buf), fp)) && row < 19) {
        if (strlen(buf) != 20) {
            break;
        }
        for (int i = 0; i < 19; i++) {
            if (!('1' <= buf[i] && buf[i] <= '6')) {
                return false;
            }
            grid->grid[row][i] = buf[i] - '1';
        }
        row++;
    }
    return row == 19;
}

typedef struct Node Node;

struct Node {
    uint64_t hash;
    float visit_counts[ncolors];
    float mean_cost[ncolors];
    float sse[ncolors];
};

#define iters 15000
#define pool_size 32768
#define pool_nodes (pool_size + 100)
#define pool_mask (pool_size - 1)

Node pool[pool_nodes];

void init_node(Node* node, uint64_t hash, int* surrounding_counts) {
    node->hash = hash;
    for (int i = 0; i < ncolors; i++) {
        if (surrounding_counts[i]) {
            node->visit_counts[i] = 1;
            node->mean_cost[i] = 20;
            node->sse[i] = 400;
        }
    }
}

Node* lookup_node(uint64_t hash) {
    size_t index = hash & pool_mask;
    for (int i = index;; i++) {
        uint64_t h = pool[i].hash;
        if (h == hash || !h) {
            return pool + i;
        }
    }
}

int rollout(Grid* grid, int* surrounding_counts, char* solution) {
    for (int i = 0;; i++) {
        int nonzero = 0;
        uint8_t colors[6];
        for (int i = 0; i < ncolors; i++) {
            if (surrounding_counts[i]) {
                colors[nonzero++] = i;
            }
        }
        if (!nonzero) {
            return i;
        }
        uint8_t color = colors[rand_u32() % nonzero]; 
        *(solution++) = color;
        assert(grid->boundary_size);
        memset(surrounding_counts, 0, 6 * sizeof(int));
        transition(grid, color, surrounding_counts);
    }
}

int simulate(Node* node, Grid* grid, int depth, char* solution) {
    float best_cost = INFINITY;
    uint8_t best_color = 255;
    for (int color = 0; color < ncolors; color++) {
        float n = node->visit_counts[color];
        if (node->visit_counts[color] == 0) {
            continue;
        }
        float sigma = sqrt(node->sse[color] / (n * n));
        float cost = node->mean_cost[color];
        cost = normal(cost, sigma);
        if (cost < best_cost) {
            best_color = color;
            best_cost = cost;
        }
    }
    if (best_color == 255) {
        return 0;
    }
    *solution++ = best_color;
    int score;
    int surrounding_counts[ncolors] = {0};
    transition(grid, best_color, surrounding_counts);
    Node* child = lookup_node(grid->hash);
    if (!child->hash) {
        init_node(child, grid->hash, surrounding_counts);
        score = rollout(grid, surrounding_counts, solution);
    } else {
        score = simulate(child, grid, depth + 1, solution);
    }
    score++;
    float n1 = ++node->visit_counts[best_color];
    float u0 = node->mean_cost[best_color];
    float u1 = node->mean_cost[best_color] = u0 + (score - u0) / n1;
    node->sse[best_color] += (score - u0) * (score - u1);
    return score;
}

int main(void) {
    FILE* fp;
    if (!(fp = fopen("floodtest", "r"))) {
        return 1;
    }
    Grid grid;
    init_zobrist();
    while (load_grid(fp, &grid)) {

        memset(pool, 0, sizeof(pool));
        int surrounding_counts[ncolors] = {0};

        reset_grid(&grid, surrounding_counts);
        Node root = {0};

        init_node(&root, grid.hash, surrounding_counts);

        char solution[max_steps] = {0};
        char best_solution[max_steps] = {0};

        int min_score = INT_MAX;

        uint64_t prev_hash = 0;
        uint64_t hash = 0;
        int same_count = 0;

        for (int iter = 0; iter < iters; iter++) {
            reset_grid(&grid, surrounding_counts);
            int score = simulate(&root, &grid, 1, solution);
            if (score < min_score) {
                min_score = score;
                memcpy(best_solution, solution, score);
            }
            hash = 0;
            for (int i = 0; i < score; i++) {
                hash ^= zobrist_table[i%len][(int)solution[i]];
            }
            if (hash == prev_hash) {
                same_count++;
                if (same_count >= 10) {
                    break;
                }
            } else {
                same_count = 0;
                prev_hash = hash;
            }
        }
        int i;
        for (i = 0; i < min_score; i++) {
            best_solution[i] += '1';
        }
        best_solution[i++] = '\n';
        best_solution[i++] = '\0';
        printf(best_solution);
        fflush(stdout);
    }
    return 0;
}

एल्गोरिथ्म मोंटे-कार्लो ट्री सर्च पर थॉम्पसन के नमूने के साथ आधारित है, और खोज स्थान को कम करने के लिए एक ट्रांसपोज़न टेबल है। मेरी मशीन पर लगभग 12 घंटे लगते हैं। यदि आप परिणामों की जांच करना चाहते हैं, तो आप उन्हें https://dropfile.to/pvjYDMV पर पा सकते हैं ।


उपयोगकर्ता smack42 प्रोग्राम क्रैश को ठीक hash ^= zobrist_table[i][(int)solution[i]];करने के hash ^= zobrist_table[i%len][(int)solution[i]];लिए बदलने का सुझाव देता है ।
स्टीफन

@ स्टेपहेन मैं यह नहीं देखता कि एक अंक लेन से अधिक कैसे हो सकता है। क्या आपके पास कोई इनपुट है जो यह क्रैश बनाता है? क्या आपके पास smak42 के साथ आपकी बातचीत का लिंक है? यहां तक ​​कि अगर दुर्घटना नहीं हो सकती है, मुझे लगता है कि कोड के साथ सुरक्षित पक्ष पर होने में कोई नुकसान नहीं है जो प्रदर्शन-महत्वपूर्ण नहीं है।
user1502040

नहीं, क्षमा करें, यह सुझाए गए संपादनों में था। यहाँ समीक्षा है: codegolf.stackexchange.com/review/suggested-edits/42008
स्टीफन

इस पर मेरी पिटाई के लिए +1। ); लेकिन सावधान रहना, वहाँ कुछ सुधार आने के लिए हो सकता है
tigrou

4

जावा - 2,434,108 2,588,847 चरण

वर्तमान में जीत (~ 46K हेरंजन से आगे) 4/26 के रूप में

वेल्ड, इसलिए न केवल मिबैकेंड ने मुझे हराया, बल्कि मुझे एक बग मिला जिसने एक भ्रामक अच्छा स्कोर बनाया। यह अब ठीक हो गया है (सत्यापनकर्ता में भी! Ack), लेकिन दुर्भाग्य से मेरे पास मुकुट को वापस लेने और लेने के लिए फिलहाल कोई समय नहीं है। बाद में प्रयास करेंगे।

यह मेरे अन्य समाधान के आधार पर है, लेकिन रंग के साथ सबसे आम भरने वाले किनारों पर पेंट करने के बजाय, यह उस रंग के साथ पेंट करता है जिसके परिणामस्वरूप किनारों को उजागर किया जाएगा जिसमें एक ही रंग के कई आसन्न वर्ग हैं। इसे LookAheadPainter कहें। अगर जरूरत पड़ी तो बाद में गोल्फ करूंगा।

import java.io.*;
import java.util.*;

public class LookAheadPainter {

    static final boolean PRINT_FULL_OUTPUT = true;

    public static void main(String[] a) throws IOException {

        int totalSteps = 0, numSolved = 0;

        char[] board = new char[361];
        Scanner s = new Scanner(new File("floodtest"));
        long startTime = System.nanoTime();

        caseloop: while (s.hasNextLine()) {
            for (int l = 0; l < 19; l++) {
                String line = s.nextLine();
                if (line.isEmpty())
                    continue caseloop;
                System.arraycopy(line.toCharArray(), 0, board, l * 19, 19);
            }

            List<Character> colorsUsed = new ArrayList<>();

            for (;;) {

                FillResult fill = new FillResult(board, board[180], (char) 48, null);

                if (fill.nodesFilled.size() == 361)
                    break;

                int[] branchSizes = new int[7];

                for (int i = 1; i < 7; i++) {
                    List<Integer> seeds = new ArrayList<>();
                    for (Integer seed : fill.edges)
                        if (board[seed] == i + 48)
                            seeds.add(seed);

                    branchSizes[i] = new FillResult(fill.filledBoard, (char) (i + 48), (char) 48, seeds).nodesFilled.size();
                }

                int maxSize = 0;
                char bestColor = 0;

                for (int i = 1; i < 7; i++)
                    if (branchSizes[i] > maxSize) {
                        maxSize = branchSizes[i];
                        bestColor = (char) (i + 48);
                    }

                for (int i : fill.nodesFilled)
                    board[i] = bestColor;

                colorsUsed.add(bestColor);
                totalSteps++;
            }
            numSolved++;

            if (PRINT_FULL_OUTPUT) {
                if (numSolved % 1000 == 0)
                    System.out.println("Solved: " + numSolved); // So you know it's working
                String out = "";
                for (Character c : colorsUsed)
                    out += c;
                System.out.println(out);
            }

        }
        s.close();
        System.out.println("\nTotal steps to solve all cases: " + totalSteps);
        System.out.printf("\nSolved %d test cases in %.2f seconds", numSolved, (System.nanoTime() - startTime) / 1000000000.);
    }

    private static class FillResult {

        Set<Integer> nodesFilled, edges;
        char[] filledBoard;

        FillResult(char[] board, char target, char replacement, List<Integer> seeds) {
            Stack<Integer> nodes = new Stack<>();
            nodesFilled = new HashSet<>();
            edges = new HashSet<>();

            if (seeds == null)
                nodes.push(180);
            else
                for (int i : seeds)
                    nodes.push(i);

            filledBoard = new char[361];
            System.arraycopy(board, 0, filledBoard, 0, 361);

            while (!nodes.empty()) {
                int n = nodes.pop();
                if (n < 0 || n > 360)
                    continue;
                if (filledBoard[n] == target) {
                    filledBoard[n] = replacement;
                    nodesFilled.add(n);
                    if (n % 19 > 0)
                        nodes.push(n - 1);
                    if (n % 19 < 18)
                        nodes.push(n + 1);
                    if (n / 19 > 0)
                        nodes.push(n - 19);
                    if (n / 19 < 18)
                        nodes.push(n + 19);
                } else
                    edges.add(n);
            }
        }
    }
}

संपादित करें: मैंने एक सत्यापनकर्ता लिखा है, इसका उपयोग करने के लिए स्वतंत्र महसूस करता हूं, यह एक चरण की अपेक्षा करता है। एक कदम फ़ाइल जिसमें आपके प्रोग्राम आउटपुट के साथ-साथ बाढ़ फ़ाइल भी शामिल हैं: संपादित करें-संपादित करें: (ओपी देखें)

अगर किसी को कोई समस्या मिलती है, तो कृपया मुझे इसकी सूचना दें!


अच्छा है, पिज्जा! और उस सत्यापनकर्ता वास्तव में एक स्मार्ट है! ओपी को कुछ इस तरह का / एक नियंत्रण कार्यक्रम बनाना चाहिए था (जिससे बहुत सारी समस्याएं हल हो गई होंगी)।
हर्जन

3

सी - 2,480,714 चरण

अभी भी इष्टतम नहीं है, लेकिन यह अब तेज है और बेहतर स्कोर करता है।

#include <stdio.h>
#include <string.h>
#include <stdbool.h>

char map[19][19], reach[19][19];
int reachsum[6], totalsum[6];

bool loadmap(FILE *fp)
{
    char buf[19 + 2];
    size_t row = 0;

    while (fgets(buf, sizeof buf, fp) && row < 19) {
        if (strlen(buf) != 20)
            break;
        memcpy(map[row++], buf, 19);
    }
    return row == 19;
}

void calcreach(bool first, size_t row, size_t col);
void check(char c, bool first, size_t row, size_t col)
{
    if (map[row][col] == c)
        calcreach(first, row, col);
    else if (first)
        calcreach(false, row, col);
}

void calcreach(bool first, size_t row, size_t col)
{
    char c = map[row][col];

    reach[row][col] = c;
    reachsum[c - '1']++;
    if (row < 18 && !reach[row + 1][col])
        check(c, first, row + 1, col);
    if (col < 18 && !reach[row][col + 1])
        check(c, first, row, col + 1);
    if (row > 0 && !reach[row - 1][col])
        check(c, first, row - 1, col);
    if (col > 0 && !reach[row][col - 1])
        check(c, first, row, col - 1);
}

void calctotal()
{
    size_t row, col;

    for (row = 0; row < 19; row++)
        for (col = 0; col < 19; col++)
            totalsum[map[row][col] - '1']++;
}

void apply(char c)
{
    char d = map[9][9];
    size_t row, col;

    for (row = 0; row < 19; row++)
        for (col = 0; col < 19; col++)
            if (reach[row][col] == d)
                map[row][col] = c;
}

int main()
{
    char c, best;
    size_t steps = 0;
    FILE *fp;

    if (!(fp = fopen("floodtest", "r")))
        return 1;

    while (loadmap(fp)) {
        do {
            memset(reach, 0, sizeof reach);
            memset(reachsum, 0, sizeof reachsum);
            calcreach(true, 9, 9);
            if (reachsum[map[9][9] - '1'] == 361)
                break;

            memset(totalsum, 0, sizeof totalsum);
            calctotal();

            reachsum[map[9][9] - '1'] = 0;
            for (best = 0, c = 0; c < 6; c++) {
                if (!reachsum[c])
                    continue;
                if (reachsum[c] == totalsum[c]) {
                    best = c;
                    break;
                } else if (reachsum[c] > reachsum[best]) {
                    best = c;
                }
            }

            apply(best + '1');
        } while (++steps);
    }

    fclose(fp);

    printf("steps: %zu\n", steps);
    return 0;
}

अच्छा किया विलेम, मुझे आपके विवरण में उल्लेख करने के लिए धन्यवाद। आपकी कृपा से मैं सम्मानित हूं।
हर्जन

कोई बात नहीं, प्रिय हरजन
स्टीलटर्माइट

वैसे, आपके बयान "यह हर्गन की तुलना में मामूली रूप से बेहतर है" पहले से ही पुराना है, मैंने अभी उस सुधार को लागू किया है जहां मैंने (मेल में) बात की थी;) सौभाग्य अब मुझे मार रहा है!
हर्जन

1
आप से 515 कदम आगे, कभी एक '=' को जोड़ने / हटाने के बारे में सुना, एक तुलना में,
हेह

दरअसल, हर्जन। मैं आपके सुझाव के अनुसार अपना सबमिशन अपडेट करूंगा।
स्टीलटर्माइट

3

जावा - 2,245,529 कदम

समानांतर और कैशिंग पेड़ की गहराई 5 पर खोज, "द्वीप" की संख्या कम से कम। चूँकि गहराई 4 से गहराई 5 तक का सुधार इतना छोटा था, इसलिए मुझे नहीं लगता कि इसे और सुधारने का कोई मतलब है। लेकिन अगर इसमें सुधार की आवश्यकता होती है, तो मेरी आंत की भावना सब कुछ पुनर्गणना करने के बजाय दो राज्यों के बीच एक अंतर के रूप में द्वीपों की संख्या की गणना के साथ काम करने के लिए कहती है।

वर्तमान में स्टडआउट के आउटपुट, जब तक कि मैं सत्यापनकर्ता के इनपुट प्रारूप को नहीं जानता।

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.AbstractList;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.BitSet;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveTask;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class FloodPaint {

    private static final ForkJoinPool FORK_JOIN_POOL = new ForkJoinPool();

    public static void main(String[] arg) throws IOException, InterruptedException, ExecutionException {
        try (BufferedReader reader = new BufferedReader(new FileReader("floodtest"))) {
            int sum = 0;
            State initState = readNextInitState(reader);
            while (initState != null) {
                List<Integer> solution = generateSolution(initState);
                System.out.println(solution);
                sum += solution.size();
                initState = readNextInitState(reader);
            }
            System.out.println(sum);
        }
    }

    private static State readNextInitState(BufferedReader reader) throws IOException {
        int[] initGrid = new int[State.DIM * State.DIM];
        String line = reader.readLine();
        while ((line != null) && line.isEmpty()) {
            line = reader.readLine();
        }
        if (line == null) {
            return null;
        }
        for (int rowNo = 0; rowNo < State.DIM; ++rowNo) {
            for (int colNo = 0; colNo < State.DIM; ++colNo) {
                initGrid[(State.DIM * rowNo) + colNo] = line.charAt(colNo) - '0';
            }
            line = reader.readLine();
        }
        return new State(initGrid);
    }

    private static List<Integer> generateSolution(State initState) throws InterruptedException, ExecutionException {
        List<Integer> solution = new LinkedList<>();
        StateFactory stateFactory = new StateFactory();
        State state = initState;
        while (!state.isSolved()) {
            int num = findGoodNum(state, stateFactory);
            solution.add(num);
            state = state.getNextState(num, stateFactory);
        }
        return solution;
    }

    private static int findGoodNum(State state, StateFactory stateFactory) throws InterruptedException, ExecutionException {
        SolverTask task = new SolverTask(state, stateFactory);
        FORK_JOIN_POOL.invoke(task);
        return task.get();
    }

}

class SolverTask extends RecursiveTask<Integer> {

    private static final int DEPTH = 5;

    private final State state;
    private final StateFactory stateFactory;

    SolverTask(State state, StateFactory stateFactory) {
        this.state = state;
        this.stateFactory = stateFactory;
    }

    @Override
    protected Integer compute() {
        try {
            Map<Integer,AnalyzerTask> tasks = new HashMap<>();
            for (int num = 1; num <= 6; ++num) {
                if (num != state.getCenterNum()) {
                    State nextState = state.getNextState(num, stateFactory);
                    AnalyzerTask task = new AnalyzerTask(nextState, DEPTH - 1, stateFactory);
                    tasks.put(num, task);
                }
            }
            invokeAll(tasks.values());
            int bestValue = Integer.MAX_VALUE;
            int bestNum = -1;
            for (Map.Entry<Integer,AnalyzerTask> taskEntry : tasks.entrySet()) {
                int value = taskEntry.getValue().get();
                if (value < bestValue) {
                    bestValue = value;
                    bestNum = taskEntry.getKey();
                }
            }
            return bestNum;
        } catch (InterruptedException | ExecutionException ex) {
            throw new RuntimeException(ex);
        }
    }

}

class AnalyzerTask extends RecursiveTask<Integer> {

    private static final int DEPTH_THRESHOLD = 3;

    private final State state;
    private final int depth;
    private final StateFactory stateFactory;

    AnalyzerTask(State state, int depth, StateFactory stateFactory) {
        this.state = state;
        this.depth = depth;
        this.stateFactory = stateFactory;
    }

    @Override
    protected Integer compute() {
        return (depth < DEPTH_THRESHOLD) ? analyze() : split();
    }

    private int analyze() {
        return analyze(state, depth);
    }

    private int analyze(State state, int depth) {
        if (state.isSolved()) {
            return -depth;
        }
        if (depth == 0) {
            return state.getNumIslands();
        }
        int bestValue = Integer.MAX_VALUE;
        for (int num = 1; num <= 6; ++num) {
            if (num != state.getCenterNum()) {
                State nextState = state.getNextState(num, stateFactory);
                int nextValue = analyze(nextState, depth - 1);
                bestValue = Math.min(bestValue, nextValue);
            }
        }
        return bestValue;
    }

    private int split() {
        try {
            if (state.isSolved()) {
                return -depth;
            }
            Collection<AnalyzerTask> tasks = new ArrayList<>(5);
            for (int num = 1; num <= 6; ++num) {
                State nextState = state.getNextState(num, stateFactory);
                AnalyzerTask task = new AnalyzerTask(nextState, depth - 1, stateFactory);
                tasks.add(task);
            }
            invokeAll(tasks);
            int bestValue = Integer.MAX_VALUE;
            for (AnalyzerTask task : tasks) {
                int nextValue = task.get();
                bestValue = Math.min(bestValue, nextValue);
            }
            return bestValue;
        } catch (InterruptedException | ExecutionException ex) {
            throw new RuntimeException(ex);
        }
    }

}

class StateFactory {

    private static final int INIT_CAPACITY = 40000;
    private static final float LOAD_FACTOR = 0.9f;

    private final ReadWriteLock cacheLock = new ReentrantReadWriteLock();
    private final Map<List<Integer>,State> cache = new HashMap<>(INIT_CAPACITY, LOAD_FACTOR);

    State get(int[] grid) {
        List<Integer> stateKey = new IntList(grid);
        State state;
        cacheLock.readLock().lock();
        try {
            state = cache.get(stateKey);
        } finally {
            cacheLock.readLock().unlock();
        }
        if (state == null) {
            cacheLock.writeLock().lock();
            try {
                state = cache.get(stateKey);
                if (state == null) {
                    state = new State(grid);
                    cache.put(stateKey, state);
                }
            } finally {
                cacheLock.writeLock().unlock();
            }
        }
        return state;
    }

}

class State {

    static final int DIM = 19;
    private static final int CENTER_INDEX = ((DIM * DIM) - 1) / 2;

    private final int[] grid;
    private int numIslands;

    State(int[] grid) {
        this.grid = grid;
        numIslands = calcNumIslands(grid);
    }

    private static int calcNumIslands(int[] grid) {
        int numIslands = 0;
        BitSet uncounted = new BitSet(DIM * DIM);
        uncounted.set(0, DIM * DIM);
        int index = -1;
        while (!uncounted.isEmpty()) {
            index = uncounted.nextSetBit(index + 1);
            BitSet island = new BitSet(DIM * DIM);
            generateIsland(grid, index, grid[index], island);
            ++numIslands;
            uncounted.andNot(island);
        }
        return numIslands;
    }

    private static void generateIsland(int[] grid, int index, int num, BitSet island) {
        if ((grid[index] == num) && !island.get(index)) {
            island.set(index);
            if ((index % DIM) > 0) {
                generateIsland(grid, index - 1, num, island);
            }
            if ((index % DIM) < (DIM - 1)) {
                generateIsland(grid, index + 1, num, island);
            }
            if ((index / DIM) > 0) {
                generateIsland(grid, index - DIM, num, island);
            }
            if ((index / DIM) < (DIM - 1)) {
                generateIsland(grid, index + DIM, num, island);
            }
        }
    }

    int getCenterNum() {
        return grid[CENTER_INDEX];
    }

    boolean isSolved() {
        return numIslands == 1;
    }

    int getNumIslands() {
        return numIslands;
    }

    State getNextState(int num, StateFactory stateFactory) {
        int[] nextGrid = grid.clone();
        if (num != getCenterNum()) {
            flood(nextGrid, CENTER_INDEX, getCenterNum(), num);
        }
        State nextState = stateFactory.get(nextGrid);
        return nextState;
    }

    private static void flood(int[] grid, int index, int fromNum, int toNum) {
        if (grid[index] == fromNum) {
            grid[index] = toNum;
            if ((index % 19) > 0) {
                flood(grid, index - 1, fromNum, toNum);
            }
            if ((index % 19) < (DIM - 1)) {
                flood(grid, index + 1, fromNum, toNum);
            }
            if ((index / 19) > 0) {
                flood(grid, index - DIM, fromNum, toNum);
            }
            if ((index / 19) < (DIM - 1)) {
                flood(grid, index + DIM, fromNum, toNum);
            }
        }
    }

}

class IntList extends AbstractList<Integer> implements List<Integer> {

    private final int[] arr;
    private int hashCode = -1;

    IntList(int[] arr) {
        this.arr = arr;
    }

    @Override
    public int size() {
        return arr.length;
    }

    @Override
    public Integer get(int index) {
        return arr[index];
    }

    @Override
    public Integer set(int index, Integer value) {
        int oldValue = arr[index];
        arr[index] = value;
        return oldValue;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj instanceof IntList) {
            IntList arg = (IntList) obj;
            return Arrays.equals(arr, arg.arr);
        }
        return super.equals(obj);
    }

    @Override
    public int hashCode() {
        if (hashCode == -1) {
            hashCode = 1;
            for (int elem : arr) {
                hashCode = 31 * hashCode + elem;
            }
        }
        return hashCode;
    }

}

प्रभावशाली, क्या आप इसे एक फ़ाइल के चरणों को लिख सकते हैं? ताकि हम इसकी जाँच कर सकें?
हर्जन

@ हिरण को लगता है कि उसका कोड स्व-वैध है। SeeSolved ()
BurntPizza

@BurntPizza तो? मेरा कोड भी स्व-मान्य है, योग्य ... मेरा मतलब है, कि मेरे कोड के रूप में गलत हो सकता है।
हर्जन

isSolved () सत्यापन के लिए नहीं है, यह समाप्ति के लिए है। लिखने के लिए - अगले संस्करण में करेंगे।
मीकबैकेंड

अगर एक ऐसा अनुमान लगाने वाले ने 5 कदम गहरी खोज की है तो मुझे दिलचस्पी होगी अगर 4 के लिए पाए गए चरणों की संख्या अधिक से 24अधिक कुशल रनटाइम होती।
जो जेड।

2

माई लास्ट एंट्री: C - 2,384,020 स्टेप्स

इस बार एक 'चेक-ऑल-प्रॉस्पेक्ट्स' एक ... यह स्कोर 3. सेट पर गहराई के साथ प्राप्त किया गया है। 5 पर गहराई ~ 2.1M चरण देना चाहिए ... TOO SLOW। गहराई 20+ कम से कम संभव कदम देता है (यह सिर्फ सभी मैचों की जाँच करता है और सबसे कम जीतता है) ... इसमें कम से कम चरणों की मात्रा होती है, हालांकि मुझे इससे नफरत है क्योंकि यह केवल एक छोटा सा बेहतर है, लेकिन प्रदर्शन बेकार है। मैं अपनी अन्य सी प्रविष्टि पसंद करता हूं, जो इस पोस्ट में भी है।

#include <stdio.h>
#include <string.h>
#include <stdbool.h>

char map[19][19], reach[19][19];
int reachsum[6], totalsum[6], mapCount = 0;
FILE *stepfile;

bool loadmap(FILE *fp)
{
    fprintf(stepfile, "%s", "\n");

    mapCount++;

    char buf[19 + 2];
    size_t row = 0;

    while (fgets(buf, sizeof buf, fp) && row < 19) {
        if (strlen(buf) != 20)
            break;
        memcpy(map[row++], buf, 19);
    }
    return row == 19;
}

void calcreach(bool first, size_t row, size_t col);
void check(char c, bool first, size_t row, size_t col)
{
    if (map[row][col] == c)
        calcreach(first, row, col);
    else if (first)
        calcreach(false, row, col);
}

void calcreach(bool first, size_t row, size_t col)
{
    char c = map[row][col];

    reach[row][col] = c;
    reachsum[c - '1']++;
    if (row < 18 && !reach[row + 1][col])
        check(c, first, row + 1, col);
    if (col < 18 && !reach[row][col + 1])
        check(c, first, row, col + 1);
    if (row > 0 && !reach[row - 1][col])
        check(c, first, row - 1, col);
    if (col > 0 && !reach[row][col - 1])
        check(c, first, row, col - 1);
}

void calctotal()
{
    size_t row, col;

    for (row = 0; row < 19; row++)
        for (col = 0; col < 19; col++)
            totalsum[map[row][col] - '1']++;
}

void apply(char c)
{
    char d = map[9][9];
    size_t row, col;

    for (row = 0; row < 19; row++)
        for (col = 0; col < 19; col++)
            if (reach[row][col] == d)
                map[row][col] = c;
}

int pown(int x, int y){
    int p = 1;
    for(int i = 0; i < y; i++){
        p = p * x;
    }

    return p;
}

int main()
{
    size_t steps = 0;
    FILE *fp;

    if (!(fp = fopen("floodtest", "r")))
        return 1;
    if(!(stepfile = fopen("steps.txt", "w")))
        return 1;

    const int depth = 5;
    char possibilities[pown(6, depth)][depth];
    int t = 0;
    for(int a = 0; a < 6; a++){
        for(int b = 0; b < 6; b++){
            for(int c = 0; c < 6; c++){
                for(int d = 0; d < 6; d++){
                    for(int e = 0; e < 6; e++){
                        possibilities[t][0] = (char)(a + '1');
                        possibilities[t][1] = (char)(b + '1');
                        possibilities[t][2] = (char)(c + '1');
                        possibilities[t][3] = (char)(d + '1');
                        possibilities[t++][4] = (char)(e + '1');
                    }
                }
            }
        }
    }
    poes:
    while (loadmap(fp)) {
        do {
            char map2[19][19];
            memcpy(map2, map, sizeof(map));

            memset(reach, 0, sizeof reach);
            memset(reachsum, 0, sizeof reachsum);
            calcreach(true, 9, 9);

            int best = 0, index = 0, end = depth;
            for(int i = 0; i < pown(6, depth); i++){
                for(int d = 0; d < end; d++){

                    apply(possibilities[i][d]);

                    memset(reach, 0, sizeof reach);
                    memset(reachsum, 0, sizeof reachsum);
                    calcreach(true, 9, 9);

                    if(reachsum[map[9][9] - '1'] == 361 && d < end){
                        end = d+1;
                        index = i;
                        break;
                    }
                }
                if(end == depth && best < reachsum[map[9][9] - '1']){
                    best = reachsum[map[9][9] - '1'];
                    index = i;
                }

                memcpy(map, map2, sizeof(map2));
                memset(reach, 0, sizeof reach);
                memset(reachsum, 0, sizeof reachsum);
                calcreach(true, 9, 9);
            }

            for(int d = 0; d < end; d++){

                apply(possibilities[index][d]);

                memset(reach, 0, sizeof reach);
                memset(reachsum, 0, sizeof reachsum);
                calcreach(true, 9, 9);

                fprintf(stepfile, "%c", possibilities[index][d]);
                steps++;
            }
            if(reachsum[map[9][9] - '1'] == 361)
                goto poes;
        } while (1);
    }

    fclose(fp);
    fclose(stepfile);

    printf("steps: %zu\n", steps);
    return 0;
}

C - 2,445,761 चरणों में लिखा गया एक और बेहतर AI

SteelTermite के आधार पर:

#include <stdio.h>
#include <string.h>
#include <stdbool.h>

char map[19][19], reach[19][19];
int reachsum[6], totalsum[6], mapCount = 0;
FILE *stepfile;

bool loadmap(FILE *fp)
{
    fprintf(stepfile, "%s", "\n");

    if(mapCount % 1000 == 0)
        printf("mapCount = %d\n", mapCount);

    mapCount++;

    char buf[19 + 2];
    size_t row = 0;

    while (fgets(buf, sizeof buf, fp) && row < 19) {
        if (strlen(buf) != 20)
            break;
        memcpy(map[row++], buf, 19);
    }
    return row == 19;
}

void calcreach(bool first, size_t row, size_t col);
void check(char c, bool first, size_t row, size_t col)
{
    if (map[row][col] == c)
        calcreach(first, row, col);
    else if (first)
        calcreach(false, row, col);
}

void calcreach(bool first, size_t row, size_t col)
{
    char c = map[row][col];

    reach[row][col] = c;
    reachsum[c - '1']++;
    if (row < 18 && !reach[row + 1][col])
        check(c, first, row + 1, col);
    if (col < 18 && !reach[row][col + 1])
        check(c, first, row, col + 1);
    if (row > 0 && !reach[row - 1][col])
        check(c, first, row - 1, col);
    if (col > 0 && !reach[row][col - 1])
        check(c, first, row, col - 1);
}

void calctotal()
{
    size_t row, col;

    for (row = 0; row < 19; row++)
        for (col = 0; col < 19; col++)
            totalsum[map[row][col] - '1']++;
}

void apply(char c)
{
    char d = map[9][9];
    size_t row, col;

    for (row = 0; row < 19; row++)
        for (col = 0; col < 19; col++)
            if (reach[row][col] == d)
                map[row][col] = c;
}

int main()
{
    char c, best, answer;
    size_t steps = 0;
    FILE *fp;

    if (!(fp = fopen("floodtest", "r")))
        return 1;
    if(!(stepfile = fopen("steps.txt", "w")))
            return 1;

    while (loadmap(fp)) {
        do {
            memset(reach, 0, sizeof reach);
            memset(reachsum, 0, sizeof reachsum);
            calcreach(true, 9, 9);
            if (reachsum[map[9][9] - '1'] == 361)
                break;

            memset(totalsum, 0, sizeof totalsum);
            calctotal();

            reachsum[map[9][9] - '1'] = 0;
            for (best = 0, c = 0; c < 6; c++) {
                if (!reachsum[c])
                    continue;
                if (reachsum[c] == totalsum[c]) {
                    best = c;
                    goto outLoop;
                } else if (reachsum[c] > reachsum[best]) {
                    best = c;
                }
            }

            char map2[19][19];
            memcpy(map2, map, sizeof(map));

            int temp = best;
            for(c = 0; c < 6; c++){

                if(c != best){

                    apply(c + '1');

                    memset(reach, 0, sizeof reach);
                    memset(reachsum, 0, sizeof reachsum);
                    calcreach(true, 9, 9);
                    if (reachsum[best] == totalsum[best]) {

                        memcpy(map, map2, sizeof(map2));
                        memset(reach, 0, sizeof reach);
                        memset(reachsum, 0, sizeof reachsum);
                        calcreach(true, 9, 9);

                        if(temp == -1)
                            temp = c;
                        else if(reachsum[c] > reachsum[temp])
                            temp = c;
                    }

                    memcpy(map, map2, sizeof(map2));
                    memset(reach, 0, sizeof reach);
                    memset(reachsum, 0, sizeof reachsum);
                    calcreach(true, 9, 9);
                }
            }

outLoop:    answer = (char)(temp + '1');
            fprintf(stepfile, "%c", answer);
            apply(answer);
        } while (++steps);
    }

    fclose(fp);
    fclose(stepfile);

    printf("steps: %zu\n", steps);
    return 0;
}

... और ~ 200K को हरा देना;)
MrBackend

आपको प्रत्येक प्रविष्टि को एक व्यक्तिगत उत्तर के रूप में पोस्ट करना चाहिए।
जो जेड।

@JoeZ। क्षमा करें, लेकिन यह स्पैमिंग जैसा महसूस हुआ, इसलिए मैंने उन्हें एक जवाब में इकट्ठा करने का फैसला किया (यह केवल सबसे अच्छा (सबसे अच्छा = एअर इंडिया के सबसे कम मात्रा वाले चरणों) मायने रखता है)। कम से कम मैं क्या सोचा था।
हर्जन

1

जावा - 2,610,797 4,780,841 चरण

(फिल-बग फिक्स, स्कोर अब नाटकीय रूप से बदतर है -_-)

यह मेरा मूल संदर्भ एल्गोरिथ्म सबमिशन है, बस चित्रित क्षेत्र के किनारों पर वर्गों का एक हिस्टोग्राम बनाता है, और सबसे आम रंग के साथ पेंट करता है। एक मिनट में 100k चलाता है।

जाहिर है कि जीत नहीं होगी, लेकिन यह निश्चित रूप से अंतिम नहीं है। मैं शायद चतुर सामान के लिए एक और सबमिशन करूँगा। इस एल्गोरिथ्म को शुरुआती बिंदु के रूप में उपयोग करने के लिए स्वतंत्र महसूस करें।

पूर्ण आउटपुट के लिए टिप्पणी की गई पंक्तियों को अन-कम करें। उठाए गए कदमों की # छपाई करने में चूक।

import java.io.*;
import java.util.*;

public class PainterAI {

    public static void main(String[] args) throws IOException {

        int totalSteps = 0, numSolved = 0;

        char[] board = new char[361];
        Scanner s = new Scanner(new File("floodtest"));
        long startTime = System.nanoTime();
        caseloop: while (s.hasNextLine()) {
            for (int l = 0; l < 19; l++) {
                String line = s.nextLine();
                if (line.isEmpty())
                    continue caseloop;
                System.arraycopy(line.toCharArray(), 0, board, l * 19, 19);
            }

            List<Character> colorsUsed = new ArrayList<>();
            Stack<Integer> nodes = new Stack<>();

            for (;; totalSteps++) {
                char p = board[180];
                int[] occurrences = new int[7];
                nodes.add(180);
                int numToPaint = 0;
                while (!nodes.empty()) {
                    int n = nodes.pop();
                    if (n < 0 || n > 360)
                        continue;
                    if (board[n] == p) {
                        board[n] = 48;
                        numToPaint++;
                        if (n % 19 > 0)
                            nodes.push(n - 1);
                        if(n%19<18)
                            nodes.push(n + 1);
                        if(n/19>0)
                            nodes.push(n - 19);
                        if(n/19<18)
                            nodes.push(n + 19);
                    } else
                        occurrences[board[n] - 48]++;
                }
                if (numToPaint == 361)
                    break;
                char mostFrequent = 0;
                int times = -1;
                for (int i = 1; i < 7; i++)
                    if (occurrences[i] > times) {
                        times = occurrences[i];
                        mostFrequent = (char) (i + 48);
                    }
                for (int i = 0; i < 361; i++)
                    if (board[i] == 48)
                        board[i] = mostFrequent;
                //colorsUsed.add(mostFrequent);
            }
            numSolved++;

            /*String out = "";
            for (Character c : colorsUsed)
                out += c;
            System.out.println(out); //print output*/
        }
        s.close();
        System.out.println("Total steps to solve all cases: " + totalSteps);
        System.out.printf("\nSolved %d test cases in %.2f seconds", numSolved, (System.nanoTime() - startTime) / 1000000000.);
    }
}

860 चार्ट में गोल्फ (फॉर्मेटिंग के लिए नई कड़ियों को शामिल नहीं करना), लेकिन अगर मुझे कोशिश करने का मन हुआ तो और सिकुड़ सकता है:

import java.io.*;import java.util.*;class P{
public static void main(String[]a)throws Exception{int t=0;char[]b=new char[361];
Scanner s=new Scanner(new File("floodtest"));c:while(s.hasNextLine()){
for(int l=0;l<19;l++){String L=s.nextLine();if(L.isEmpty())continue c;
System.arraycopy(L.toCharArray(),0,b,l*19,19);}List<Character>u=new ArrayList<>();
Stack<Integer>q=new Stack<>();for(int[]o=new int[7];;t++){char p=b[180];q.add(180);
int m=0;while(!q.empty()){int n=q.pop();if(n<0|n>360)continue;if(b[n]==p){b[n]=48;m++;
if(n%19>0)q.add(n-1);if(n%19<18)q.add(n+1);if(n/19>0)q.add(n-19);if(n/19<18)
q.add(n+19);}else o[b[n]-48]++;}if(m==361)break;
char f=0;int h=0;for(int i=1;i<7;i++)if(o[i]>h){h=o[i];f=(char)(i+48);}
for(int i=0;i<361;i++)if(b[i]==48)b[i]=f;u.add(f);}String y="";for(char c:u)y+=c;
System.out.println(y);}s.close();System.out.println("Steps: "+t);}}

एकमात्र कारण यह "निश्चित रूप से अंतिम नहीं है" क्योंकि मेरा संदर्भ समाधान चीजों को पैड करने के लिए है। यह वास्तव में इस समय अन्य लोगों द्वारा सभी प्रस्तुतियाँ से बाहर अंतिम स्थान पर है: पी
जो जेड।

@JoeZ। खैर यह स्टीलटर्माइट्स के सामने था, लेकिन उसने अपनी स्थिति में सुधार किया। मेरा मतलब "भोलेपन से अगला तार्किक कदम" है। मैं चिंतित होता अगर यह अच्छा कर रहा होता, पी
बर्नटजिज़ा

1

हास्केल - 2,475,056 चरण

अल्गोरिथम टिप्पणियों में MrBackend द्वारा सुझाए गए एक के समान है। अंतर यह है: उनका सुझाव उच्चतम लागत वर्ग के लिए सबसे सस्ता रास्ता ढूंढता है, मेरा लालच हर कदम पर ग्राफ सनकीपन को कम करता है।

import Data.Array
import qualified Data.Map as M
import Data.Word
import Data.List
import Data.Maybe
import Data.Function (on)
import Data.Monoid
import Control.Arrow
import Control.Monad (liftM)
import System.IO
import System.Environment
import Control.Parallel.Strategies
import Control.DeepSeq

type Grid v = Array (Word8,Word8) v

main = do
  (ifn:_) <- getArgs
  hr <- openFile ifn ReadMode
  sp <- liftM parseFile $ hGetContents hr
  let (len,sol) = turns (map solve sp `using` parBuffer 3 (evalList rseq))
  putStrLn $ intercalate "\n" $ map (concatMap show) sol
  putStrLn $ "\n\nTotal turns: " ++ (show len)

turns :: [[a]] -> (Integer,[[a]])
turns l = rl' 0 l where
  rl' c [] = (c,[])
  rl' c (k:r) = let
   s = c + genericLength k
   (s',l') = s `seq` rl' s r
   in (s',k:l')

centrepoint :: Grid v -> (Word8,Word8)
centrepoint g = let
  ((x0,y0),(x1,y1)) = bounds g
  med l h = let t = l + h in t `div` 2 + t `mod` 2
  in (med x0 x1, med y0 y1)

neighbours :: Grid v -> (Word8,Word8) -> [(Word8,Word8)]
neighbours g (x,y) = filter
  (inRange $ bounds g)
  [(x,y+1),(x+1,y),(x,y-1),(x-1,y)]

areas :: Eq v => Grid v -> [[(Word8,Word8)]]
areas g = p $ indices g where
  p [] = []
  p (a:r) = f : p (r \\ f) where
    f = s g [a] []
s g [] _ = []
s g (h:o) v = let
  n = filter (((==) `on` (g !)) h) $ neighbours g h
  in h : s g ((n \\ (o ++ v)) ++ o) (h : v)

applyFill :: Eq v => v -> Grid v -> Grid v
applyFill c g = g // (zip fa $ repeat c) where
  fa = s g [centrepoint g] []

solve g = solve' gr' where
  aa = areas g
  cp = centrepoint g
  ca = head $ head $ filter (elem cp) aa
  gr' = M.fromList $ map (
    \r1 -> (head r1, map head $ filter (
      \r2 -> head r1 /= head r2 &&
        (not $ null $ intersect (concatMap (neighbours g) r1) r2)
     ) aa
    )
   ) aa
  solve' gr
    | null $ tail $ M.keys $ gr = []
    | otherwise = best : solve' ngr where
      djk _ [] = []
      djk v ((n,q):o) = (n,q) : djk (q:v) (
        o ++ zip (repeat (n+1))
        ((gr M.! q) \\ (v ++ map snd o))
       )
      dout = djk [] [(0,ca)]
      din = let
        m = maximum $ map fst dout
        s = filter ((== m) . fst) dout
        in djk [] s
      rc = filter (flip elem (gr M.! ca) . snd) din
      frc = let
        m = minimum $ map fst rc
        in map snd $ filter ((==m) . fst) rc
      msq = concat $ filter (flip elem frc . head) aa
      clr = map (length &&& head) $ group $ sort $ map (g !) msq
      best = snd $ maximumBy (compare `on` fst) clr
      ngr = let
        ssm = filter ((== best) . (g !)) $ map snd rc
        sml = (concatMap (gr M.!) ssm)
        ncl = ((gr M.! ca) ++ sml) \\ (ca : ssm)
        brk = M.insert ca ncl $ M.filterWithKey (\k _ ->
          (not . flip elem ssm) k
         ) gr
        in M.map 
          (\l -> nub $ map (\e -> if e `elem` ssm then ca else e) l)
          brk


parseFile :: String -> [Grid Word8]
parseFile f = map mk $ filter (not . null . head) $ groupBy ((==) `on` null) $
  map (map ((read :: String -> Word8) . (:[]))) $ lines f where
    mk :: [[Word8]] -> Grid Word8
    mk m = let
      w = fromIntegral (length $ head m) - 1
      h = fromIntegral (length m) - 1
      in array ((0,0),(w,h)) [ ((x,y),v) |
        (y,l) <- zip [h,h-1..] m,
        (x,v) <- zip [0..] l
       ]

showGrid :: Grid Word8 -> String
showGrid g = intercalate "\n" l where
  l = map sl $ groupBy ((==) `on` snd) $
    sortBy ((flip (compare `on` snd)) <> (compare `on` fst)) $
    indices g
  sl = intercalate " " . map (show . (g !))

testsolve = do
  hr <- openFile "floodtest" ReadMode
  sp <- liftM (head . parseFile) $ hGetContents hr
  let
   sol = solve sp
   a = snd $ mapAccumL (\g s -> let g' = applyFill s g in (g',g')) sp sol
  sequence_ $ map (\g -> putStrLn (showGrid g) >> putStrLn "\n") a

क्या यह अभी तक चल रहा है?
जो जेड।

अभी तक नहीं, यह अब तक समाप्त हो जाता अगर मैं इसे रात भर चलने देता, लेकिन पंखा शोर करता था इसलिए मैंने कंप्यूटर को हाइबरनेट कर दिया। यह अब फिर से चल रहा है, जब मैं घर से काम पर जाऊंगा तो फिर से जांच करूंगा।
जेरेमी सूची

यह एक स्टैक ओवरफ्लो के कारण दुर्घटनाग्रस्त हो गया, जिससे बचने के लिए अब संशोधित किया गया है।
जेरेमी सूची

1

सी # - 2,383,569

यह संभावित समाधानों की गहराई से गहराई है जो मोटे तौर पर सर्वोत्तम सुधार का मार्ग चुनता है (मैं के अलावा हरजन की सी प्रविष्टि के समान / समान) बड़ी आसानी से उम्मीदवार समाधान पीढ़ी के आदेश को उलट दिया, देखने के बाद हरजन ने उसी संख्याओं को पोस्ट किया। हालांकि चलाने के लिए एक अच्छा 12+ घंटे लगते हैं।

class Solver
{
    static void Main()
    {
        int depth = 3;
        string text = File.ReadAllText(@"C:\TEMP\floodtest.txt");
        text = text.Replace("\n\n", ".").Replace("\n", "");
        int count = 0;
        string[] tests = text.Split(new char[] { '.' }, StringSplitOptions.RemoveEmptyEntries);
        for (int i = 0; i < tests.Length; i++)
        {
            Solver s = new Solver(tests[i]);
            string k1 = s.solve(depth);
            count += k1.Length;
            Console.WriteLine(((100 * i) / tests.Length) + " " + i + " " + k1.Length + " " + count + " " + k1);
        }
        Console.WriteLine(count);
    }

    public readonly int MAX_DIM;
    public char[] board;
    public Solver(string prob)
    {
        board = read(prob);
        MAX_DIM = (int)Math.Sqrt(board.Length);
    }

    public string solve(int d)
    {
        var sol = "";
        while (score(eval(copy(board), sol)) != board.Length)
        {
            char[] b = copy(board);
            eval(b, sol);

            var canidates = new List<string>();
            buildCanidates("", canidates, d);
            var best = canidates.Select(c => new {score = score(eval(copy(b), c)), sol = c}).ToList().OrderByDescending(t=>t.score).ThenBy(v => v.sol.Length).First();
            sol = sol + best.sol[0];
        }
        return sol;
    }

    public void buildCanidates(string b, List<string> r, int d)
    {
        if(b.Length>0)
            r.Add(b);
        if (d > 0)
        {
            r.Add(b);
            for (char i = '6'; i >= '1'; i--)
                if(b.Length == 0 || b[b.Length-1] != i)
                    buildCanidates(b + i, r, d - 1);
        }
    }

    public char[] read(string s)
    {
        return s.Where(c => c >= '0' && c <= '9').ToArray();
    }

    public void print(char[] b)
    {
        for (int i = 0; i < MAX_DIM; i++)
        {
            for(int j=0; j<MAX_DIM; j++)
                Console.Write(b[i*MAX_DIM+j]);
            Console.WriteLine();
        }
        Console.WriteLine();
    }

    public char[] copy(char[] b)
    {
        char[] n = new char[b.Length];
        for (int i = 0; i < b.Length; i++)
            n[i] = b[i];
        return n;
    }

    public char[] eval(char[] b, string sol)
    {
        foreach (char c in sol)
            eval(b, c);
        return b;
    }

    public void eval(char[] b, char c)
    {
        foreach (var l in flood(b))
            b[l] = c;
    }

    public int score(char[] b)
    {
        return flood(b).Count;
    }

    public List<int> flood(char[] b)
    {
        int start = (MAX_DIM * (MAX_DIM / 2)) + (MAX_DIM / 2);
        var check = new List<int>(MAX_DIM * MAX_DIM);
        bool[] seen = new bool[b.Length];
        var hits = new List<int>(MAX_DIM*MAX_DIM);

        check.Add(start);
        seen[start]=true;
        char target = b[start];

        int at = 0;
        while (at<check.Count)
        {
            int toCheck = check[at++];
            if (b[toCheck] == target)
            {
                addNeighbors(check, seen, toCheck);
                hits.Add(toCheck);
            }
        }
        return hits;
    }

    public void addNeighbors(List<int> check, bool[] seen, int loc)
    {
        int x = loc / MAX_DIM;
        int y = loc % MAX_DIM;
        addNeighbor(check, seen, x, y - 1);
        addNeighbor(check, seen, x, y + 1);
        addNeighbor(check, seen, x - 1, y);
        addNeighbor(check, seen, x + 1, y);
    }

    public void addNeighbor(List<int> check, bool[] seen, int x, int y)
    {
        if (x >= 0 && x < MAX_DIM && y >= 0 && y < MAX_DIM)
        {
            int l = (x * MAX_DIM) + y;
            if (!seen[l])
            {
                seen[l] = true;
                check.Add(l);
            }
        }
    }
}

1

जावा - 2,403,189

BUILD SUCCESSFUL (total time: 220 minutes 15 seconds)

यह एक क्रूर बल पर मेरा प्रयास माना जाता था। परंतु! सिंगल-डेप्थ "बेस्ट" पसंद का मेरा पहला कार्यान्वयन हुआ:

2,589,328 - BUILD SUCCESSFUL (total time: 3 minutes 11 seconds)

दोनों के लिए उपयोग किया जाने वाला कोड अन्य संभावित चालों के "स्नैपशॉट" को संग्रहीत करने और उन सभी पर एल्गोरिथ्म चलाने के लिए जानवर के बल के साथ समान है।


  • मुद्दे

यदि "मल्टी" पास दृष्टिकोण के साथ चल रहा है तो यादृच्छिक विफलताएं होंगी। मैंने पहले 100 पहेली प्रविष्टियों को एक इकाई परीक्षण में सेट किया है और 100% पास प्राप्त कर सकता है लेकिन समय का 100% नहीं। क्षतिपूर्ति करने के लिए, मैंने बस वर्तमान पहेली संख्या को विफल समय पर ट्रैक किया और एक नया थ्रेड चुनना शुरू कर दिया, जहां पिछले एक ने छोड़ दिया। प्रत्येक थ्रेड ने एक फ़ाइल के लिए अपने संबंधित परिणाम लिखे। फ़ाइल पूल को तब एकल फ़ाइल में सम्मिलित किया गया था।

  • पहुंच

Nodeबोर्ड के एक टाइल / वर्ग का प्रतिनिधित्व करता है और इसके सभी पड़ोसियों के लिए एक संदर्भ संग्रहीत करता है। तीन ट्रैक Set<Node>चर: Remaining,Painted , Targets। प्रत्येक पुनरावृति मान को चुनकर, Targetsसभी candidateनोड्स को समूह में देखता हैtarget value "प्रभावित" नोड की संख्या से है। ये प्रभावित नोड्स फिर अगले पुनरावृत्ति के लिए लक्ष्य बन जाते हैं।

स्रोत कई वर्गों में फैला हुआ है और स्निपेट्स पूरे संदर्भ से बहुत सार्थक नहीं हैं। मेरे स्रोत के माध्यम से ब्राउज़ किया जा सकता है GitHub के है । मैं भी एक JSFiddle के साथ गड़बड़ कर दी विज़ुअलाइज़ेशन के लिए डेमो के ।

फिर भी, मेरे workhorse विधि से Solver.java:

public void flood() {

 final Data data = new Data();
 consolidateCandidates(data, targets);

 input.add(data.getTarget());

 if(input.size() > SolutionRepository.getInstance().getThreshold()){
  //System.out.println("Exceeded threshold: " + input.toString());
  cancelled = true;
 }
 paintable.addAll(data.targets());
 remaining.removeAll(data.targets());

 if(!data.targets().isEmpty()){
  targets = data.potentialTargets(data.targets(), paintable);

  data.setPaintable(paintable);
  data.setRemaining(remaining);
  data.setInput(input);

  SolutionRepository.getInstance().addSnapshot(data, input);
 }
}

1

सी # - 2,196,462 2,155,834

यह प्रभावी रूप से मेरे अन्य सॉल्वर के रूप में समान रूप से 'सबसे अच्छा वंशज' दृष्टिकोण है, लेकिन कुछ अनुकूलन के साथ, जो कि बमुश्किल, समानता के साथ, इसे 10 घंटे से कम में 5 गहराई तक जाने की अनुमति देता है। इस परीक्षण के दौरान मुझे मूल में एक बग भी मिला, जैसे कि एल्गोरिथ्म कभी-कभी अक्षम मार्गों को अंतिम स्थिति में ले जाएगा (यह स्कोर = 64 वाले राज्यों की गहराई का हिसाब नहीं दे रहा था; गहराई के परिणामों के साथ रहते हुए खोजा गया; = 7)।

इस और पिछले सॉल्वर के बीच मुख्य अंतर यह है कि यह फ्लड गेम स्टेट्स को मेमोरी में बनाए रखता है, इसलिए इसे 6 ^ 5 राज्यों को फिर से बनाने की आवश्यकता नहीं है। रनिंग के दौरान सीपीयू के उपयोग के आधार पर, मैं काफी निश्चित हूं कि यह सीपीयू से मेमोरी बैंडविड्थ बाउंड से स्थानांतरित हो गया है। बहुत मज़ा। इतने पाप।

संपादित करें: कारणों के कारण, गहराई 5 एल्गोरिथ्म हमेशा सबसे अच्छा परिणाम नहीं देता है। प्रदर्शन में सुधार करने के लिए, चलो बस 5 गहराई करें ... और 4 ... और 3 और 2 और 1, और देखें कि कौन सा सबसे अच्छा है। एक और 40k चाल से दाढ़ी बनाई। चूंकि गहराई 5 समय का बड़ा हिस्सा है, इसलिए 1 के माध्यम से 4 को जोड़ने से केवल 10hrs से ~ 11hrs तक रनटाइम बढ़ता है। वाह!

using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Collections.Generic;

public class Program
{
    static void Main()
    {
        int depth = 5;
        string text = File.ReadAllText(@"C:\TEMP\floodtest.txt");
        text = text.Replace("\n\n", ".").Replace("\n", "");
        int count = 0;
        string[] tests = text.Split(new [] { '.' }, StringSplitOptions.RemoveEmptyEntries);

        Stopwatch start = Stopwatch.StartNew();

        const int parChunk = 16*16;
        for (int i = 0; i < tests.Length; i += parChunk)
        {
            //did not know that parallel select didn't respect order
            string[] sols = tests.Skip(i).Take(parChunk).AsParallel().Select((t, idx) => new { s = new Solver2(t).solve(depth), idx}).ToList().OrderBy(v=>v.idx).Select(v=>v.s).ToArray();
            for (int j = 0; j < sols.Length; j++)
            {
                string k1 = sols[j];
                count += k1.Length;
                int k = i + j;
                int estimate = (int)((count*(long)tests.Length)/(k+1));
                Console.WriteLine(k + "\t" + start.Elapsed.TotalMinutes.ToString("F2") + "\t" + count + "\t" + estimate + "\t" + k1.Length + "\t" + k1);
            }
        }
        Console.WriteLine(count);
    }
}

public class Solver2
{
    public readonly int MAX_DIM;
    public char[] board;
    public Solver2(string prob)
    {
        board = read(prob);
        MAX_DIM = (int)Math.Sqrt(board.Length);
    }

    public string solve(int d)
    {
        string best = null;
        for (int k = d; k >= 1; k--)
        {
            string c = subSolve(k);
            if (best == null || c.Length < best.Length)
                best = c;
        }
        return best;
    }

    public string subSolve(int d)
    {
        State current = new State(copy(board), '\0', flood(board));
        var sol = "";

        while (current.score != board.Length)
        {
            State nextState = subSolve(current, d);
            sol = sol + nextState.key;
            current = nextState;
        }
        return sol;
    }

    public State subSolve(State baseState, int d)
    {
        if (d == 0)
            return baseState;
        if (!baseState.childrenGenerated)
        {
            for (int i = 0; i < baseState.children.Length; i++)
            {
                if (('1' + i) == baseState.key) continue; //no point in even eval'ing
                char[] board = copy(baseState.board);
                foreach(int idx in baseState.flood)
                    board[idx] = (char)('1' + i);
                List<int> f = flood(board);
                if (f.Count != baseState.score)
                    baseState.children[i] = new State(board, (char)('1' + i), f);
            }
            baseState.childrenGenerated = true;
        }
        State bestState = null;

        for (int i = 0; i < baseState.children.Length; i++)
            if (baseState.children[i] != null)
            {
                State bestChild = subSolve(baseState.children[i], d - 1);
                baseState.children[i].bestChildScore = bestChild.bestChildScore;
                if (bestState == null || bestState.bestChildScore < bestChild.bestChildScore)
                    bestState = baseState.children[i];
            }
        if (bestState == null || bestState.bestChildScore == baseState.score)
        {
            if (baseState.score == baseState.board.Length)
                baseState.bestChildScore = baseState.score*(d + 1);
            return baseState;
        }
        return bestState;
    }

    public char[] read(string s)
    {
        return s.Where(c => c >= '1' && c <= '6').ToArray();
    }

    public char[] copy(char[] b)
    {
        char[] n = new char[b.Length];
        for (int i = 0; i < b.Length; i++)
            n[i] = b[i];
        return n;
    }

    public List<int> flood(char[] b)
    {
        int start = (MAX_DIM * (MAX_DIM / 2)) + (MAX_DIM / 2);
        var check = new List<int>(MAX_DIM * MAX_DIM);
        bool[] seen = new bool[b.Length];
        var hits = new List<int>(MAX_DIM * MAX_DIM);

        check.Add(start);
        seen[start] = true;
        char target = b[start];

        int at = 0;
        while (at < check.Count)
        {
            int toCheck = check[at++];
            if (b[toCheck] == target)
            {
                addNeighbors(check, seen, toCheck);
                hits.Add(toCheck);
            }
        }
        return hits;
    }

    public void addNeighbors(List<int> check, bool[] seen, int loc)
    {
        //int x = loc / MAX_DIM;
        int y = loc % MAX_DIM;

        if(loc+MAX_DIM < seen.Length)
            addNeighbor(check, seen, loc+MAX_DIM);
        if(loc-MAX_DIM >= 0)
            addNeighbor(check, seen, loc-MAX_DIM);
        if(y<MAX_DIM-1)
            addNeighbor(check, seen, loc+1);
        if (y > 0)
            addNeighbor(check, seen, loc-1);
    }

    public void addNeighbor(List<int> check, bool[] seen, int l)
    {
        if (!seen[l])
        {
            seen[l] = true;
            check.Add(l);
        }
    }
}

public class State
{
    public readonly char[] board;
    public readonly char key;
    public readonly State[] children = new State[6];
    public readonly List<int> flood; 
    public readonly int score;
    public bool childrenGenerated;
    public int bestChildScore;
    public State(char[] board, char k, List<int> flood)
    {
        this.board = board;
        key = k;
        this.flood = flood;
        score = flood.Count;
        bestChildScore = score;
    }
}

मैंने आपका कोड आज़माया और यह संकलन नहीं है। एक हल विधि कॉल के पास एक त्रुटि है। इसके अलावा, कुछ "गायब" बयानों का उपयोग करना भी है। वैसे भी, यदि आपका कार्यक्रम 2.1M चरणों में सब कुछ हल करता है, तो बधाई देता है, यह प्रभावशाली है।
बाघिन

@tigrou मुझे बयानों का उपयोग करने में कोई समस्या नहीं है; हल कॉल त्रुटि को ठीक किया- यह कोड को फिर से अपडेट करने के बजाय इसे कॉपी करने (कॉपी / पेस्ट) करने की कोशिश कर रहा था। उसके लिए क्षमा चाहता हूँ।
कोडरताओ

blarg। आप == नामस्थान आयात का उपयोग कर रहे थे। उसे भी ठीक कर रहे हैं।
कोडरताओ

CPU का उपयोग आप सभी बोर्डों को 5 से 11 घंटे में गहराई से हल करने के लिए करते हैं? मैंने I5 760@2.8Ghz के तहत कार्यक्रम चलाया है। 256 बोर्डों में से प्रत्येक चंक को आउटपुट करने में 30 मिनट लग गए। उसके आधार पर, 100.000 बोर्डों को हल करने में 8 दिन लगेंगे। सीपीयू उस दौरान 80-100% उपयोग के बीच उछल रहा था, सभी चार कोर का उपयोग किया गया था। हो सकता है कि कोई मुद्दा वर्चुअलबॉक्स मशीन है जो परीक्षणों को चलाने के लिए उपयोग किया जाता है, लेकिन यह आपके मुकाबले लगभग 16 गुना गुना धीमा है (आपने कहा था कि इसमें 11 घंटे लगते हैं)।
tigrou

@tigrou मैं एक i5 750@2.67 (3-4 साल पुराने हार्डवेयर) पर चल रहा हूं। वीएस के तहत, डिबग बनाम रिलीज़ मोड में 50% अंतर है, लेकिन मुझे संदेह है कि यह 16x अंतर की व्याख्या करेगा। यदि आप एक लिनक्स होस्ट के तहत दौड़ रहे हैं, तो आप मोनो के साथ संकलन करने की कोशिश कर सकते हैं
कोडरताओ

1

डेल्फी एक्सई 3 2,979,145 कदम

ठीक है, तो यह मेरा प्रयास है। मैं बदलते हिस्से को एक बूँद कहता हूं, प्रत्येक मोड़ यह सरणी की एक प्रति बना देगा और यह देखने के लिए हर संभव रंग का परीक्षण करेगा कि कौन सा रंग सबसे बड़ा बूँद देगा।

सभी पहेली को 3 घंटे और 6 मिनट में चलाता है

program Main;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  SysUtils,
  Classes,
  Generics.Collections,
  math,
  stopwatch in 'stopwatch.pas';

type
  myArr=array[0..1]of integer;
const
  MaxSize=19;
  puzLoc='here is my file';
var
  L:TList<TList<integer>>;
  puzzles:TStringList;
  sc:TList<myArr>;
  a:array[0..MaxSize-1,0..MaxSize-1] of Integer;
  aTest:array[0..MaxSize-1,0..MaxSize-1] of Integer;
  turns,midCol,sX,sY,i:integer;
  currBlob,biggestBlob,ColorBigBlob:integer;
  sTurn:string='';
  GLC:integer=0;

procedure FillArrays;
var
  ln,x,y:integer;
  puzzle:TStringList;
begin
  sc:=TList<myArr>.Create;
  puzzle:=TStringList.Create;    
  while puzzle.Count<19 do
  begin
    if puzzles[GLC]='' then
    begin
      inc(GLC);
      continue
    end
    else
      puzzle.Add(puzzles[GLC]);
    inc(GLC)
  end;    
  for y:=0to MaxSize-1do
    for x:=0to MaxSize-1do
      a[y][x]:=Ord(puzzle[y][x+1])-48;
  puzzle.Free;
end;
function CreateArr(nx,ny:integer):myArr;
begin
  Result[1]:=nx;
  Result[0]:=ny;
end;

procedure CreateBlob;
var
  tst:myArr;
  n,tx,ty:integer;
  currColor:integer;
begin
  n:=0;
  sc.Clear;
  currColor:=a[sy][sx];
  sc.Add(CreateArr(sx,sy));
  repeat
    tx:=sc[n][1];
    ty:=sc[n][0];
    if tx>0 then
      if a[ty][tx-1]=currColor then
      begin
        tst:=CreateArr(tx-1,ty);
        if not sc.Contains(tst)then
          sc.Add(tst);
      end;
    if tx<MaxSize-1 then
      if a[ty][tx+1]=currColor then
      begin
        tst:=CreateArr(tx+1,ty);
        if not sc.Contains(tst)then
          sc.Add(tst);
      end;
    if ty>0 then
      if a[ty-1][tx]=currColor then
      begin
        tst:=CreateArr(tx,ty-1);
        if not sc.Contains(tst)then
          sc.Add(tst);
      end;
    if ty<MaxSize-1 then
      if a[ty+1][tx]=currColor then
      begin
        tst:=CreateArr(tx,ty+1);
        if not sc.Contains(tst)then
          sc.Add(tst);
      end;
    inc(n);
  until (n=sc.Count);
end;

function BlobSize:integer;
var
  L:TList<myArr>;
  tst:myArr;
  n,currColor,tx,ty:integer;
begin
  n:=0;
  L:=TList<myArr>.Create;
  currColor:=aTest[sy][sx];
  L.Add(CreateArr(sx,sy));

  repeat
    tx:=L[n][1];
    ty:=L[n][0];
    if tx>0then
      if aTest[ty][tx-1]=currColor then
      begin
        tst:=CreateArr(tx-1,ty);
        if not L.Contains(tst)then
          L.Add(tst);
      end;
    if tx<MaxSize-1then
      if aTest[ty][tx+1]=currColor then
      begin
        tst:=CreateArr(tx+1,ty);
        if not L.Contains(tst)then
          L.Add(tst);
      end;
    if ty>0then
      if aTest[ty-1][tx]=currColor then
      begin
        tst:=CreateArr(tx,ty-1);
        if not L.Contains(tst)then
          L.Add(tst);
      end;
    if ty<MaxSize-1then
      if aTest[ty+1][tx]=currColor then
      begin
        tst:=CreateArr(tx,ty+1);
        if not L.Contains(tst)then
          L.Add(tst);
      end;
    inc(n);
  until n=l.Count;
  Result:=L.Count;
  L.Free;
end;

function AllsameColor(c:integer):boolean;
var
  cy,cx:integer;
begin
  Result:=true;
  for cy:=0to MaxSize-1do
    for cx:=0to MaxSize-1do
      if a[cy][cx]=c then
        continue
      else
        exit(false);
end;
procedure ChangeColors(old,new:integer; testing:boolean=false);
var
  i,j:integer;
  tst:myArr;
begin
  if testing then
  begin
    for i:= 0to MaxSize-1do
      for j:= 0to MaxSize-1do
        aTest[i][j]:=a[i][j];    
    for I:=0to sc.Count-1do
    begin
      tst:=sc[i];
      aTest[tst[0]][tst[1]]:=new;
    end;
  end
  else
  begin
    for I:=0to sc.Count-1do
    begin
      tst:=sc[i];
      a[tst[0]][tst[1]]:=new;
    end;
  end;
end;
var
  sw, swTot:TStopWatch;
  solved:integer=0;
  solutions:TStringList;
  steps:integer;
  st:TDateTime;
begin          
  st:=Now;
  writeln(FormatDateTime('hh:nn:ss',st));
  solutions:=TStringList.Create;
  puzzles:=TStringList.Create;
  puzzles.LoadFromFile(puzLoc);
  swTot:=TStopWatch.Create(true);
  turns:=0;
  repeat
    sTurn:='';    
    FillArrays;
    sX:=Round(Sqrt(MaxSize))+1;
    sY:=sX;    
    repeat
      biggestBlob:=0;
      ColorBigBlob:=0;
      midCol:=a[sy][sx];
      CreateBlob;
      for I:=1to 6do
      begin
        if I=midCol then continue;    
        ChangeColors(midCol,I,true);
        currBlob:=BlobSize;
        if currBlob>biggestBlob then
        begin
          biggestBlob:=currBlob;
          ColorBigBlob:=i;
        end;
      end;
      ChangeColors(midCol,ColorBigBlob);
      inc(turns);
      if sTurn='' then
        sTurn:=IntToStr(ColorBigBlob)
      else
        sTurn:=sTurn+', '+IntToStr(ColorBigBlob);
    until AllsameColor(a[sy][sx]);
    solutions.Add(sTurn);
    inc(solved);
    if solved mod 100=0then
      writeln(Format('Solved %d puzzles || %s',[solved,FormatDateTime('hh:nn:ss',Now-st)]));    
  until GLC>=puzzles.Count-1;    
  swTot.Stop;
  WriteLn(Format('solving these puzzles took %d',[swTot.Elapsed]));
  writeln(Format('Total moves: %d',[turns]));
  solutions.SaveToFile('save solutions here');
  readln;
end.

एक bruteforce backtracing विधि के बारे में भी सोच रहा था।
शायद इस सप्ताहांत के लिए मजेदार ^ ^


0

जावास्क्रिप्ट / नोड.जेएस - 2,588,847

अल्गोरिटम थोड़ा अलग है तो यहां सबसे अधिक है क्योंकि यह पूर्वगामी क्षेत्रों का उपयोग करता है और गणनाओं के बीच अंतर करता है। यह यहां 10 मिनट से कम चलता है यदि आप जावास्क्रिप्ट के कारण गति के बारे में चिंतित हैं।

var fs = require('fs')


var file = fs.readFileSync('floodtest','utf8');
var boards = file.split('\n\n');
var linelength  = boards[0].split('\n')[0].length;
var maxdim = linelength* linelength;


var board = function(info){
    this.info =[];
    this.sameNeighbors = [];
    this.differentNeighbors = [];
    this.samedifferentNeighbors = [];
    for (var i = 0;i <info.length;i++ ){
        this.info.push(info[i]|0);
    };

    this.getSameAndDifferentNeighbors();
}

board.prototype.getSameAndDifferentNeighbors = function(){
    var self = this;
    var info = self.info;
    function getSameNeighbors(i,value,sameneighbors,diffneighbors){

        var neighbors = self.getNeighbors(i);
        for(var j =0,nl = neighbors.length; j< nl;j++){
            var index = neighbors[j];
            if (info[index]  === value ){
                if( sameneighbors.indexOf(index) === -1){
                    sameneighbors.push(index);
                    getSameNeighbors(index,value,sameneighbors,diffneighbors);
                }
            }else if( diffneighbors.indexOf(index) === -1){
                    diffneighbors.push(index);
            }
        } 

    }


    var sneighbors = [];
    var dneighbors = [];
    var sdneighbors = [];

    for(var i= 0,l= maxdim;i<l;i++){
        if (sneighbors[i] === undefined){
            var sameneighbors = [i];
            var diffneighbors = [];
            getSameNeighbors(i,info[i],sameneighbors,diffneighbors);
            for (var j = 0; j<sameneighbors.length;j++){
                var k = sameneighbors[j];
                sneighbors[k] = sameneighbors;
                dneighbors[k] = diffneighbors;
            } 
        }

    }

    for(var i= 0,l= maxdim;i<l;i++){
        if (sdneighbors[i] === undefined){
            var value = [];
            var dni = dneighbors[i];
            for (var j = 0,dnil = dni.length; j<dnil;j++){
                var dnij = dni[j];
                var sdnij = sneighbors[dnij];
                for(var k = 0,sdnijl = sdnij.length;k<sdnijl;k++){
                    if (value.indexOf(sdnij[k])=== -1){
                        value.push(sdnij[k]);
                    }
                }
            };
            var sni = sneighbors[i];
            for (var j=0,snil = sni.length;j<snil;j++){
                sdneighbors[sni[j]] = value;
            };
        };
    }
    this.sameNeighbors = sneighbors;
    this.differentNeighbors =  dneighbors;
    this.samedifferentNeighbors =sdneighbors;

}

board.prototype.getNeighbors = function(i){
        var returnValue = [];

        var index = i-linelength;
        if (index >= 0){
            returnValue.push(index);
        }

        index = i+linelength;
        if (index < maxdim){

            returnValue.push(index);
        }

        index = i-1;

        if (index >= 0 && index/linelength >>> 0 === i/linelength  >>> 0){
            returnValue.push(index);
        }
        index = i+1;
        if (index/linelength >>> 0 === i/linelength >>> 0){
            returnValue.push(index);
        }

        if (returnValue.indexOf(-1) !== -1){
            console.log(i,parseInt(index/linelength,10),parseInt(i/linelength,10));
        } 
        return returnValue 
}

board.prototype.solve = function(){
    var i,j;
    var info = this.info;
    var sameNeighbors = this.sameNeighbors;
    var samedifferentNeighbors = this.samedifferentNeighbors;
    var middle = 9*19+9;
    var maxValues = [];

    var done = {};
    for (i=0; i<sameNeighbors[middle].length;i++){
        done[sameNeighbors[middle][i]] = true;
    }
    var usefullNeighbors = [[],[],[],[],[],[],[]];
    var diff = [];
    var count = [0];

    count[1] = 0;
    count[2] = 0;
    count[3] = 0;
    count[4] = 0;
    count[5] = 0;
    count[6] = 0;

    var addusefullNeighbors = function(index,diff){

        var indexsamedifferentNeighbors =samedifferentNeighbors[index];
        for (var i=0;i < indexsamedifferentNeighbors.length;i++){
            var is = indexsamedifferentNeighbors[i];
            var value = info[is];
            if (done[is] === undefined && usefullNeighbors[value].indexOf(is) === -1){
                usefullNeighbors[value].push(is);
                diff.push(value);
            }

        }
    }
    addusefullNeighbors(middle,diff);


    while(  usefullNeighbors[1].length > 0 || usefullNeighbors[2].length > 0 ||
            usefullNeighbors[3].length > 0 || usefullNeighbors[4].length > 0 ||
            usefullNeighbors[5].length > 0 || usefullNeighbors[6].length > 0 ){
        for (i=0;i < diff.length;i++){ 
            count[diff[i]]++;
        };
        var maxValue = count.indexOf(Math.max.apply(null, count));
        diff.length = 0;
        var used = usefullNeighbors[maxValue];
        for (var i=0,ul = used.length;i < ul;i++){
            var index = used[i];
            if (info[index] === maxValue){
                done[index] = true;
                addusefullNeighbors(index,diff);
            }
        }
        used.length = 0;
        count[maxValue] = 0;


        maxValues.push(maxValue);
    }
    return maxValues.join("");
};
var solved = [];
var start = Date.now();
for (var boardindex =0;boardindex < boards.length;boardindex++){ 
    var b = boards[boardindex].replace(/\n/g,'').split('');
    var board2 = new board(b);
    solved.push(board2.solve());
};
var diff = Date.now()-start;
console.log(diff,boards.length);
console.log(solved.join('').length);
console.log("end");

fs.writeFileSync('solution.txt',solved.join('\n'),'utf8');

-3

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

बाढ़ भराव अत्यंत अक्षम है और पुनरावृत्ति पर निर्भर करता है। यदि यह बहुत छोटा है तो अपने स्टैक को बड़ा बनाने की आवश्यकता हो सकती है। ब्रूट फोर्स सिस्टम सभी संभावित विकल्पों के माध्यम से संख्याओं को पकड़ने के लिए एक स्ट्रिंग और सरल ऐड-टू-कैरी का उपयोग करता है। यह भी बेहद अक्षम है क्योंकि यह समय के अधिकांश चरणों को दोहराता है।

दुर्भाग्य से, मैं इसे सभी परीक्षण मामलों के खिलाफ परीक्षण करने में असमर्थ था, क्योंकि मैं इसे खत्म करने से पहले बुढ़ापे की मृत्यु हो जाऊंगा।

#include <stdio.h>
#include <string.h>


#define GRID_SIZE       19

char grid[GRID_SIZE][GRID_SIZE] = { {3,3,5,4,1,3,4,1,5,3,3,5,4,1,3,4,1,5},
                                    {5,1,3,4,1,1,5,2,1,3,3,5,4,1,3,4,1,5},
                                    {6,5,2,3,4,3,3,4,3,3,3,5,4,1,3,4,1,5},
                                    {4,4,4,5,5,5,4,1,4,3,3,5,4,1,3,4,1,5},
                                    {6,2,5,3,3,1,1,6,6,3,3,5,4,1,3,4,1,5},
                                    {5,5,1,2,5,2,6,6,3,3,3,5,4,1,3,4,1,5},
                                    {6,1,1,5,3,6,2,3,6,3,3,5,4,1,3,4,1,5},
                                    {1,2,2,4,5,3,5,1,2,3,3,5,4,1,3,4,1,5},
                                    {3,6,6,1,5,1,3,2,4,3,3,5,4,1,3,4,1,5} };
char grid_save[GRID_SIZE][GRID_SIZE];

char test_grids[6][GRID_SIZE][GRID_SIZE];

void flood_fill(char x, char y, char old_colour, char new_colour)
{
    if (grid[y][x] == new_colour)
        return;

    grid[y][x] = new_colour;

    if (y > 0)
    {
        if (grid[y-1][x] == old_colour)
            flood_fill(x, y-1, old_colour, new_colour);
    }
    if (y < GRID_SIZE - 1)
    {
        if (grid[y+1][x] == old_colour)
            flood_fill(x, y+1, old_colour, new_colour);
    }

    if (x > 0)
    {
        if (grid[y][x-1] == old_colour)
            flood_fill(x-1, y, old_colour, new_colour);
    }
    if (x < GRID_SIZE - 1)
    {
        if (grid[y][x+1] == old_colour)
            flood_fill(x+1, y, old_colour, new_colour);
    }
}

bool check_grid(void)
{
    for (char i = 0; i < 6; i++)
    {
        if (!memcmp(grid, &test_grids[i][0][0], sizeof(grid)))
            return(true);
    }

    return(false);
}

void inc_string_num(char *s)
{
    char *c;

    c = s + strlen(s) - 1;
    *c += 1;

    // carry
    while (*c > '6')
    {
        *c = '1';
        if (c == s) // first char
        {
            strcat(s, "1");
            return;
        }
        c--;
        *c += 1;
    }
}

void print_grid(void)
{
    char x, y;
    for (y = 0; y < GRID_SIZE; y++)
    {
        for (x = 0; x < GRID_SIZE; x++)
            printf("%d ", grid[y][x]);
        printf("\n");
    }
    printf("\n");
}

int main(int argc, char* argv[])
{
    // create test grids for comparisons
    for (char i = 0; i < 6; i++)
        memset(&test_grids[i][0][0], i+1, GRID_SIZE*GRID_SIZE);

    char s[256] = "0";
    //char s[256] = "123456123456123455";
    memcpy(grid_save, grid, sizeof(grid));


    print_grid();
    do
    {
        memcpy(grid, grid_save, sizeof(grid));
        inc_string_num(s);

        for (unsigned int i = 0; i < strlen(s); i++)
        {
            flood_fill(4, 4, grid[4][4], s[i] - '0');
        }
    } while(!check_grid());
    print_grid();

    printf("%s\n", s);

    return 0;
}

जहां तक ​​मैं बता सकता हूं कि यह मौजूदा विजेता है। प्रतियोगिता की आवश्यकता है कि:

आपका कार्यक्रम पूरी तरह से निर्धारक होना चाहिए; छद्म आयामी समाधान की अनुमति है, लेकिन कार्यक्रम को हर बार एक ही परीक्षण मामले के लिए एक ही आउटपुट उत्पन्न करना चाहिए।

चेक

जीतने वाला कार्यक्रम इस फ़ाइल में पाए गए सभी 100,000 परीक्षण मामलों को हल करने के लिए कम से कम कुल कदम उठाएगा (ज़िप्ड पाठ फ़ाइल, 14.25 एमबी)। यदि दो समाधान समान संख्या में कदम उठाते हैं (जैसे कि यदि वे दोनों इष्टतम रणनीति पाते हैं), तो छोटा कार्यक्रम जीत जाएगा।

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

#include <stdio.h>
#include <string.h>
#define A 9
int g[A][A]={{3,3,5,4,1,3,4,1,5},{5,1,3,4,1,1,5,2,1},{6,5,2,3,4,3,3,4,3},{4,4,4,5,5,5,4,1,4},{6,2,5,3,3,1,1,6,6},{5,5,1,2,5,2,6,6,3},{6,1,1,5,3,6,2,3,6},{1,2,2,4,5,3,5,1,2},{3,6,6,1,5,1,3,2,4}};
int s[A][A];
int t[6][A][A];
void ff(int x,int y,int o,int n)
{if (g[y][x]==n)return;g[y][x]=n;if (y>0){if(g[y-1][x]==o)ff(x,y-1,o,n);}if(y<A-1){if(g[y+1][x]==o)ff(x,y+1,o,n);}if(x>0){if (g[y][x-1] == o)ff(x-1,y,o,n);}if(x<A-1){if(g[y][x+1]==o)ff(x+1,y,o,n);}}
bool check_g(void)
{for(int i=0;i<6;i++){if(!memcmp(g,&t[i][0][0],sizeof(g)))return(true);}return(0);}
void is(char*s){char*c;c=s+strlen(s)-1;*c+=1;while(*c>'6'){*c='1';if (c==s){strcat(s,"1");return;}c--;*c+=1;}}
void pr(void)
{int x, y;for(y=0;y<A;y++){for(x=0;x<A;x++)printf("%d ",g[y][x]);printf("\n");}printf("\n");}
int main(void)
{for(int i=0;i<6;i++)memset(&t[i][0][0],i+1,A*A);char s[256]="0";memcpy(s,g,sizeof(g));pr();do{memcpy(g,s,sizeof(g));is(s);for(int i=0;i<strlen(s);i++){ff(4,4,g[4][4],s[i]-'0');}}while(!check_g());
pr();printf("%s\n",s);return 0;}

अब तक यह एकमात्र प्रविष्टि है जिसे हर बार सबसे इष्टतम समाधान मिलता है। मेरा तर्क है कि यह एक बेहतर अंतिम स्थान संदर्भ समाधान भी है। वास्तव में, मुझे विश्वास नहीं है कि वास्तव में एक बेहतर तरीका है जो हर मामले में एक इष्टतम समाधान प्राप्त करने की गारंटी देता है, और अब तक किसी और ने अन्यथा साबित नहीं किया है।
उपयोगकर्ता

1
जब तक आप वास्तव में चरणों की सही संख्या लगेगा पा सकते हैं, मैं इस समाधान को स्वीकार नहीं कर सकते हैं, भले ही यह है (सैद्धांतिक) सबसे अच्छा एक।
जो जेड।

इसके अलावा, ग्रिड का आकार 19 है, 9. नहीं
जो जेड।

ठीक है, मैंने ग्रिड का आकार तय किया। क्या किसी को पता है कि आवश्यक चरणों की सैद्धांतिक न्यूनतम संख्या की गणना कैसे करें?
उपयोगकर्ता

नहीं। आपको इसके लिए हल करने के लिए एक कार्यक्रम का उपयोग करना होगा, जो कि अभी आपके पास है।
जो जेड।
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.