การหลอมรวมดอกไม้ไฟ


13

ภาพรวม

รับรายการดอกไม้ไฟa-zและเวลา3-78จัดเรียงฟิวส์ให้สว่างในเวลาที่ถูกต้อง

บรรทัดของอินพุตถูกกำหนดเป็นตัวอักษรและตัวเลขคั่นด้วยช่องว่าง:

a 3 b 6 c 6 d 8 e 9 f 9

ว่าตัวอย่างแสดงให้เห็นว่าพลุaจำเป็นต้องแสงในเวลา3, bและcทั้งที่6, dที่8มีeและทั้งที่f 9แต่ละบรรทัดสอดคล้องกับแผนที่เดียว

เอาท์พุทเป็นแผนที่ฟิวส์ / ดอกไม้ไฟสำหรับแต่ละบรรทัดโดยใช้สัญลักษณ์|-เพื่อแสดงฟิวส์และตัวอักษรเพื่อแสดงดอกไม้ไฟ

-เชื่อมต่อฟิวส์ฟิวส์และดอกไม้ไฟซ้ายโดยตรง / ขวาของมันในขณะที่|เชื่อมต่อกับผู้ที่ฟิวส์เหนือ / ด้านล่าง ยกตัวอย่างเช่นฟิวส์||จะไม่ได้เชื่อมต่อและมี-|

ตัวอย่างเช่นสองคำตอบที่เป็นไปได้ข้างต้นคือ:

---a        ---------f
  |         |||   ||
  |-c       |||   de
--|--d      a||
| b |        |c
f   e        b

แผนที่ฟิวส์ทั้งหมดควรเริ่มต้นด้วยซิงเกิล-ที่มุมซ้ายบน นั่นคือจุดที่คุณจุดชนวนฟิวส์ ฟิวส์แต่ละตัวใช้เวลาหนึ่งวินาทีในการเผา อย่างที่คุณเห็นการaเข้าถึงนั้นจะเกิดขึ้นในสามวินาทีในไดอะแกรมทั้งสองbในหกและอื่น ๆ

ตอนนี้แผนที่ทั้งสองที่ให้ไว้ด้านบนนั้นใช้ได้สำหรับอินพุตที่ให้ แต่ก็มีประสิทธิภาพชัดเจนกว่า ด้านซ้ายใช้ฟิวส์ 13 ยูนิตเท่านั้นในขณะที่ด้านขวาใช้ 20

ฟิวส์จะไม่ถูกเผาไหม้ด้วยดอกไม้ไฟ! ดังนั้นสำหรับอินพุตa 3 b 5สิ่งนี้ไม่ถูกต้อง:

---a--b

ท้าทาย

เป้าหมายของคุณคือลดจำนวนฟิวส์ที่ใช้กับกรณีทดสอบทั้งหมด การให้คะแนนเป็นเรื่องง่ายมากคือใช้จำนวนฟิวส์ทั้งหมด

หากคุณไม่สามารถสร้างแผนที่สำหรับกรณีทดสอบไม่ว่าจะเป็นกรณีที่เป็นไปไม่ได้หรือไม่คะแนนสำหรับกรณีนั้นคือผลรวมของทุกครั้ง (41 สำหรับตัวอย่างด้านบน)

ในกรณีที่เสมอคะแนนจะถูกปรับเปลี่ยนเพื่อให้แผนที่ขนาดกะทัดรัดที่สุดชนะ คะแนน tiebreak เป็นพื้นที่ของกล่องขอบเขตของแต่ละแผนที่ นั่นคือความยาวของบรรทัดที่ยาวที่สุดคูณด้วยจำนวนบรรทัด สำหรับแผนที่ "เป็นไปไม่ได้" นี่คือสี่เหลี่ยมที่มีจำนวนมากที่สุด (81 สำหรับตัวอย่างด้านบน)

ในกรณีที่การส่งผลเสมอทั้งสองวิธีการให้คะแนนเสมอไปที่รายการ / แก้ไขก่อนหน้า

โปรแกรมของคุณจะต้องกำหนดไว้ล่วงหน้าเพื่อการตรวจสอบ

กรณีทดสอบ

มี 250 กรณีทดสอบจะตั้งอยู่ที่นี่ แต่ละแห่งมีดอกไม้ไฟระหว่าง 4 ถึง 26 แห่ง เวลาต่ำสุดฟิวส์สำหรับพลุเป็น 3. ดอกไม้ไฟในแต่ละกรณีเป็น "เรียง" โดยเวลาและตัวอักษรที่มีความหมายbจะไม่เบาก่อน a

เมื่อโพสต์โปรดรวมโปรแกรมเต็มคะแนนรวมของคุณและแผนที่ผลลัพธ์สำหรับ (อย่างน้อย) กรณีทดสอบแรกที่ให้ไว้ในไฟล์:

a 6 b 8 c 11 d 11 e 11 f 11 g 12 h 15 i 18 j 18 k 21 l 23 m 26 n 28 o 28 p 30 q 32 r 33 s 33 t 34 

ดอกไม้ไฟจำนวนมากสามารถพลขึ้นไปพร้อมกันได้ไหม?
Ingo Bürk

โดยทั่วไปแล้วใช่ ฉันไม่ได้ค้นหาอินสแตนซ์ที่ใหญ่ที่สุดของกรณีทดสอบ แต่ฉันรู้ว่าอย่างน้อยสี่ตัว เวลาระหว่างสองฟิวส์คือrand.nextInt(5)%4โอกาส 40% 0และ 20% สำหรับแต่ละ1,2,3ครั้ง
Geobits

เพียงข้อเสนอแนะ: ฉันจะใช้ '+' เพื่อให้ฟิวส์เชื่อมต่อหรือเปลี่ยนทิศทางซึ่งจะทำให้กราฟิกเอาต์พุต IMHO ใช้งานง่ายยิ่งขึ้น!
ข้อบกพร่อง

@ flawr ฉันจะอนุญาตให้ทำในลักษณะที่จะไม่เปลี่ยนคะแนน ตัวอย่างเช่นในกรณี-+-ที่---จะไม่เชื่อมต่อดอกไม้ไฟด้านบน / ด้านล่างโดยอัตโนมัติจะต้องมีส่วน|บน / ด้านล่างเพื่อเชื่อมต่อกับดอกไม้ไฟ -+-แทนที่-|-มันก็โอเคอย่างที่มันเป็น
Geobits

กรณีทดสอบทั้งหมดสามารถแก้ไขได้หรือไม่? เช่นถ้ามีการจุดพลุดอกไม้ไฟห้าครั้งขึ้นไปในเวลา 3 ฉันไม่คิดว่าคุณจะพอดีกับพวกเขาทั้งหมดใกล้ถึงจุดเริ่มต้น ในทำนองเดียวกันคุณอาจจะพอดีกับทุกคน แต่พวกเขาอาจปิดกั้นทางด้านนอกสำหรับดอกไม้ไฟในภายหลัง
Martin Ender

คำตอบ:


3

C ++

ความยาวรวม: 9059, พื้นที่ทั้งหมด: 27469, ความล้มเหลว: 13

หมายเหตุ:คะแนนรวมบทลงโทษที่ล้มเหลว


ตัวอย่างผลลัพธ์:

a 6 b 8 c 11 d 11 e 11 f 11 g 12 h 15 i 18 j 18 k 21 l 23 m 26 n 28 o 28 p 30 q 32 r 33 s 33 t 34 
------ae  
     | |  
     |---c
     b||-g
      |d| 
      f | 
    i---| 
  k---| h 
   |  j   
   |---m  
   l  | t 
     o-n| 
      |s-r
      |-| 
      p q 
Length: 39, Area: 150.

a 6 b 6 c 6 d 6 e 6 f 6 g 6 h 8 i 9 j 9 k 9 l 12 m 12 n 13 o 14 p 15 q 15 r 15 s 17 t 17 u 17 v 17 w 17 x 20 y 23 z 26 
------a  n|--w 
|d-||---k|-o|  
| g|b  |--m --x
|-|c    ||--r| 
||f     l|-q | 
||--j u--|--s|-
e|-i    |p|  y|
 h      v t  z-
Length: 56, Area: 120.

ผลลัพธ์เต็ม: http://pastebin.com/raw.php?i=spBUidBV


คุณไม่เพียงรักการแก้ปัญหาที่โหดร้ายใช่ไหม นี่เป็นมากกว่าอัลกอริธึมย้อนรอยง่ายๆ: ผู้ทำงานที่ไม่เหน็ดเหนื่อยของเราเคลื่อนที่ไปรอบ ๆ แผนที่วางฟิวส์และดอกไม้ไฟตามที่จำเป็นขณะทดสอบการเคลื่อนไหวที่เป็นไปได้ทุกจุด ทีนี้เกือบ --- เรา จำกัด ชุดของการเคลื่อนไหวและละทิ้งสถานะ nonoptimal ก่อนเพื่อที่จะไม่ใช้เวลานานเหลือทน (และโดยเฉพาะอย่างยิ่งเพื่อที่จะยุติ) การดูแลเป็นพิเศษจะไม่สร้างวงจรใด ๆ หรือไม่ตั้งใจ เส้นทางและไม่ให้กลับไปทางเดียวกับที่เราเดินทางมาดังนั้นจึงรับประกันได้ว่าเราจะไม่ไปเยี่ยมชมรัฐเดียวกันสองครั้ง ดังนั้นการหาทางออกที่ดีที่สุดอาจใช้เวลาสักครู่ดังนั้นในที่สุดเราก็ยอมแพ้ในการปรับแก้ปัญหาให้เหมาะสมหากใช้เวลานานเกินไป

อัลกอริทึมนี้ยังมีห้องว่าง อีกประการหนึ่งการแก้ปัญหาที่ดีกว่าสามารถพบได้โดยเพิ่มFRUSTRATIONพารามิเตอร์ ไม่มีตู้ ATM แข่งขัน แต่ตัวเลขเหล่านี้สามารถ cranked ขึ้นเมื่อ ...

รวบรวมกับ: g++ fireworks.cpp -ofireworks -std=c++11 -pthread -O3.

./fireworksทำงานด้วย:

อ่านอินพุตจาก STDIN และเขียนเอาต์พุตไปยัง STDOUT (อาจล้าสมัย)

/* Magic numbers */
#define THREAD_COUNT 2
/* When FRUSTRATION_MOVES moves have passed since the last solution was found,
 * the last (1-FRUSTRATION_STATES_BACKOFF)*100% of the backtracking states are
 * discarded and FRUSTRATION_MOVES is multiplied by FRUSTRATION_MOVES_BACKOFF.
 * The lower these values are, the faster the algorithm is going to give up on
 * searching for better solutions. */
#define FRUSTRATION_MOVES 1000000
#define FRUSTRATION_MOVES_BACKOFF 0.8
#define FRUSTRATION_STATES_BACKOFF 0.5

#include <iostream>
#include <vector>
#include <algorithm>
#include <utility>
#include <thread>
#include <mutex>
#include <string>
#include <sstream>
#include <cassert>

using namespace std;

/* A tile on the board. Either a fuse, a firework, an empty tile or an
 * out-of-boudns tile. */
struct tile {
    /* The tile's value, encoded the "obvious" way (i.e. '-', '|', 'a', etc.)
     * Empty tiles are encoded as '\0' and OOB tiles as '*'. */
    char value;
    /* For fuse tiles, the time at which the fuse is lit. */
    int time;

    operator char&() { return value; }
    operator const char&() const { return value; }

    bool is_fuse() const { return value == '-' || value == '|'; }
    /* A tile is vacant if it's empty or OOB. */
    bool is_vacant() const { return !value || value == '*'; }

    /* Prints the tile. */
    template <typename C, typename T>
    friend basic_ostream<C, T>& operator<<(basic_ostream<C, T>& os,
                                            const tile& t) {
        return os << (t.value ? t.value : ' ');
    }
};
/* Fireworks have the same encoding as tiles. */
typedef tile firework;
typedef vector<firework> fireworks;

/* The fuse map. It has physical dimensions (its bounding-box) but is
 * conceptually infinite (filled with empty tiles.) */
class board {
    /* The tiles, ordered left-to-right top-to-bottom. */
    vector<tile> p_data;
    /* The board dimensions. */
    int p_width, p_height;
    /* The total fuse length. */
    int p_length;

public:
    board(): p_width(0), p_height(0), p_length(0) {}

    /* Physical dimensions. */
    int width() const { return p_width; }
    int height() const { return p_height; }
    int area() const { return width() * height(); }
    /* Total fuse length. */
    int length() const { return p_length; }

    /* Returns the tile at (x, y). If x or y are negative, returns an OOB
     * tile. */
    tile get(int x, int y) const {
        if (x < 0 || y < 0)
            return {'*'};
        else if (x >= width() || y >= height())
            return {'\0'};
        else
            return p_data[y * width() + x];
    }
    /* Sets the tile at (x, y). x and y must be nonnegative and the tile at
     * (x, y) must be empty. */
    board& set(int x, int y, const tile& t) & {
        assert(x >= 0 && y >= 0);
        assert(!get(x, y));
        if (x >= width() || y >= height()) {
            int new_width = x >= width() ? x + 1 : width();
            int new_height = y >= height() ? y + 1 : height();
            vector<tile> temp(new_width * new_height, {'\0'});
            for (int l = 0; l < height(); ++l)
                copy(
                    p_data.begin() + l * width(),
                    p_data.begin() + (l + 1) * width(),
                    temp.begin() + l * new_width
                );
            p_data.swap(temp);
            p_width = new_width;
            p_height = new_height;
        }
        p_data[y * width() + x] = t;
        if (t.is_fuse())
            ++p_length;
        return *this;
    }
    board&& set(int x, int y, const tile& t) && { return move(set(x, y, t)); }

    /* Prints the board. */
    template <typename C, typename T>
    friend basic_ostream<C, T>& operator<<(basic_ostream<C, T>& os,
                                            const board& b) {
        for (int y = 0; y < b.height(); ++y) {
            for (int x = 0; x < b.width(); ++x)
                os << b.get(x, y);
            os << endl;
        }
        return os;
    }
};

/* A state of the tiling algorithm. */
struct state {
    /* The current board. */
    board b;
    /* The next firework to tile. */
    fireworks::const_iterator fw;
    /* The current location. */
    int x, y;
    /* The current movement direction. 'N'orth 'S'outh 'E'ast, 'W'est or
     * 'A'ny. */
    char dir;
};

/* Adds a state to the state-stack if its total fuse length and bounding-box
 * area are not worse than the current best ones. */
void add_state(vector<state>& states, int max_length, int max_area,
                state&& new_s) {
    if (new_s.b.length() < max_length ||
        (new_s.b.length() == max_length && new_s.b.area() <= max_area)
    )
        states.push_back(move(new_s));
}
/* Adds the state after moving in a given direction, if it's a valid move. */
void add_movement(vector<state>& states, int max_length, int max_area,
                    const state& s, char dir) {
    int x = s.x, y = s.y;
    char parallel_fuse;
    switch (dir) {
    case 'E': if (s.dir == 'W') return; ++x; parallel_fuse = '|'; break;
    case 'W': if (s.dir == 'E') return; --x; parallel_fuse = '|'; break;
    case 'S': if (s.dir == 'N') return; ++y; parallel_fuse = '-'; break;
    case 'N': if (s.dir == 'S') return; --y; parallel_fuse = '-'; break;
    }
    const tile t = s.b.get(s.x, s.y), nt = s.b.get(x, y);
    assert(t.is_fuse());
    if (nt.is_fuse() && !(t == parallel_fuse && nt == parallel_fuse))
        add_state(states, max_length, max_area, {s.b, s.fw, x, y, dir});
}
/* Adds the state after moving in a given direction and tiling a fuse, if it's a
 * valid move. */
void add_fuse(vector<state>& states, int max_length, int max_area,
                const state& s, char dir, char fuse) {
    int x = s.x, y = s.y;
    int sgn;
    bool horz;
    switch (dir) {
    case 'E': ++x; sgn = 1; horz = true; break;
    case 'W': --x; sgn = -1; horz = true; break;
    case 'S': ++y; sgn = 1; horz = false; break;
    case 'N': --y; sgn = -1; horz = false; break;
    }
    if (s.b.get(x, y))
        /* Tile is not empty. */
        return;
    /* Make sure we don't create cycles or reconnect a firework. */
    const tile t = s.b.get(s.x, s.y);
    assert(t.is_fuse());
    if (t == '-') {
        if (horz) {
            if (fuse == '-') {
                if (!s.b.get(x + sgn, y).is_vacant() ||
                    s.b.get(x, y - 1) == '|' ||
                    s.b.get(x, y + 1) == '|')
                    return;
            } else {
                if (s.b.get(x + sgn, y) == '-' ||
                    !s.b.get(x, y - 1).is_vacant() ||
                    !s.b.get(x, y + 1).is_vacant())
                    return;
            }
        } else {
            if (!s.b.get(x, y + sgn).is_vacant() ||
                s.b.get(x - 1, y) == '-' ||
                s.b.get(x + 1, y) == '-')
                return;
        }
    } else {
        if (!horz) {
            if (fuse == '|') {
                if (!s.b.get(x, y + sgn).is_vacant() ||
                    s.b.get(x - 1, y) == '-' ||
                    s.b.get(x + 1, y) == '-')
                    return;
            } else {
                if (s.b.get(x, y + sgn) == '|' ||
                    !s.b.get(x - 1, y).is_vacant() ||
                    !s.b.get(x + 1, y).is_vacant())
                    return;
            }
        } else {
            if (!s.b.get(x + sgn, y).is_vacant() ||
                s.b.get(x, y - 1) == '|' ||
                s.b.get(x, y + 1) == '|')
                return;
        }
    }
    /* Ok. */
    add_state(
        states,
        max_length,
        max_area,
        {board(s.b).set(x, y, {fuse, t.time + 1}), s.fw, x, y, dir}
    );
}
/* Adds the state after adding a firework at the given direction, if it's a
 * valid move. */
void add_firework(vector<state>& states, int max_length, int max_area,
                    const state& s, char dir) {
    int x = s.x, y = s.y;
    int sgn;
    bool horz;
    switch (dir) {
    case 'E': ++x; sgn = 1; horz = true; break;
    case 'W': --x; sgn = -1; horz = true; break;
    case 'S': ++y; sgn = 1; horz = false; break;
    case 'N': --y; sgn = -1; horz = false; break;
    }
    if (s.b.get(x, y))
        /* Tile is not empty. */
        return;
    /* Make sure we don't run into an undeliberate fuse. */
    if (horz) {
        if (s.b.get(x + sgn, y) == '-' || s.b.get(x, y - 1) == '|' ||
            s.b.get(x, y + 1) == '|')
            return;
    } else {
        if (s.b.get(x, y + sgn) == '|' || s.b.get(x - 1, y) == '-' ||
            s.b.get(x + 1, y) == '-')
            return;
    }
    /* Ok. */
    add_state(
        states,
        max_length,
        max_area,
        /* After adding a firework, we can move in any direction. */
        {board(s.b).set(x, y, {*s.fw}), s.fw + 1, s.x, s.y, 'A'}
    );
}
void add_possible_moves(vector<state>& states, int max_length, int max_area,
                        const state& s) {
    /* We add the new states in reverse-desirability order. The most
     * (aesthetically) desirable states are added last. */

    const tile t = s.b.get(s.x, s.y);
    assert(t.is_fuse());

    /* Move in all (possible) directions. */
    for (char dir : "WENS")
        if (dir) add_movement(states, max_length, max_area, s, dir);

    /* If the fuse is too short for the next firework, keep adding fuse. */
    if (t.time < s.fw->time) {
        if (t == '-') {
            add_fuse(states, max_length, max_area, s, 'N', '|');
            add_fuse(states, max_length, max_area, s, 'S', '|');
            add_fuse(states, max_length, max_area, s, 'W', '|');
            add_fuse(states, max_length, max_area, s, 'W', '-');
            add_fuse(states, max_length, max_area, s, 'E', '|');
            add_fuse(states, max_length, max_area, s, 'E', '-');
        } else {
            add_fuse(states, max_length, max_area, s, 'W', '-');
            add_fuse(states, max_length, max_area, s, 'E', '-');
            add_fuse(states, max_length, max_area, s, 'N', '-');
            add_fuse(states, max_length, max_area, s, 'N', '|');
            add_fuse(states, max_length, max_area, s, 'S', '-');
            add_fuse(states, max_length, max_area, s, 'S', '|');
        }
    } else if (t.time == s.fw->time) {
        /* If we have enough fuse for the next firework, place the firework (if
         * possible) and don't add more fuse, or else we'll never finish... */
        if (t == '-') {
            add_firework(states, max_length, max_area, s, 'W');
            add_firework(states, max_length, max_area, s, 'E');
        } else {
            add_firework(states, max_length, max_area, s, 'N');
            add_firework(states, max_length, max_area, s, 'S');
        }
    }
}

void thread_proc(mutex& lock, int& total_length, int& total_area,
                    int& failures) {
    fireworks fw;
    vector<state> states;

    while (true) {
        /* Read input. */
        string input;
        {
            lock_guard<mutex> lg(lock);

            while (!cin.eof() && input.empty())
                getline(cin, input);
            if (input.empty())
                break;
        }
        fw.clear();
        int length = 0, area;
        {
            stringstream is;
            is << input;
            while (!is.eof()) {
                char c;
                int t;
                if (is >> c >> t) {
                    /* Fireworks must be sorted by launch time. */
                    assert(fw.empty() || t >= fw.back().time);
                    fw.push_back({c, t});
                    length += t;
                }
            }
            assert(!fw.empty());
            area = fw.back().time * fw.back().time;
        }

        /* Add initial state. */
        states.push_back({board().set(0, 0, {'-', 1}), fw.begin(), 0, 0, 'A'});

        board solution;
        int moves = 0;
        int frustration_moves = FRUSTRATION_MOVES;

        while (!states.empty()) {
            /* Check for solutions (all fireworks consumed.) */
            while (!states.empty() && states.back().fw == fw.end()) {
                state& s = states.back();
                /* Did we find a better solution? */
                if (solution.area() == 0 || s.b.length() < length ||
                    (s.b.length() == length && s.b.area() < area)
                ) {
                    solution = move(s.b);
                    moves = 0;
                    length = solution.length();
                    area = solution.area();
                }
                states.pop_back();
            }

            /* Expand the top state. */
            if (!states.empty()) {
                state s = move(states.back());
                states.pop_back();
                add_possible_moves(states, length, area, s);
            }

            /* Getting frustrated? */
            ++moves;
            if (moves > frustration_moves) {
                /* Get rid of some data. */
                states.erase(
                    states.begin() + states.size() * FRUSTRATION_STATES_BACKOFF,
                    states.end()
                );
                frustration_moves *= FRUSTRATION_MOVES_BACKOFF;
                moves = 0;
            }
        }

        /* Print solution. */
        {
            lock_guard<mutex> lg(lock);

            cout << input << endl;

            if (solution.area())
                cout << solution;
            else {
                cout << "FAILED!" << endl;
                ++failures;
            }

            cout << "Length: " << length <<
                    ", Area: " << area <<
                    "." << endl << endl;
            total_length += length;
            total_area += area;
        }
    }
}

int main(int argc, const char* argv[]) {
    thread threads[THREAD_COUNT];
    mutex lock;
    int total_length = 0, total_area = 0, failures = 0;

    for (int i = 0; i < THREAD_COUNT; ++i)
        threads[i] = thread(thread_proc, ref(lock), ref(total_length),
                            ref(total_area), ref(failures));
    for (int i = 0; i < THREAD_COUNT; ++i)
        threads[i].join();

    cout << "Total Length: " << total_length <<
            ", Total Area: " << total_area <<
            ", Failures: " << failures <<
            "." << endl;
}

หลาม

ความยาวทั้งหมด: 17387, พื้นที่ทั้งหมด: 62285, ความล้มเหลว: 44


ตัวอย่างผลลัพธ์:

a 6 b 8 c 11 d 11 e 11 f 11 g 12 h 15 i 18 j 18 k 21 l 23 m 26 n 28 o 28 p 30 q 32 r 33 s 33 t 34
------a                
     |----f            
     |---c             
     b|||---h          
      |dg  |           
      e    |-j         
           |---k       
           i  |        
              |---m    
              l  |-o   
                 |--p  
                 n |--s
                   |-r 
                   q|  
                    t  
Length: 45, Area: 345.

ผลลัพธ์เต็ม: http://pastebin.com/raw.php?i=mgiqXCRK


สำหรับการอ้างอิงนี่เป็นวิธีที่ง่ายกว่ามาก มันพยายามเชื่อมต่อดอกไม้ไฟกับเส้นฟิวส์หลักเส้นเดียวสร้างรูปร่าง "บันได" หากดอกไม้ไฟไม่สามารถเชื่อมต่อกับสายหลักโดยตรง (ซึ่งเกิดขึ้นเมื่อแสงดอกไม้ไฟสองจุดขึ้นไปในเวลาเดียวกัน) มันจะย้อนกลับไปที่สายหลักเพื่อมองหาจุดที่สามารถแยกสาขาลงหรือไปทางขวา (และล้มเหลวถ้า ไม่มีประเด็นดังกล่าว)

แปลกใจที่มันไม่เลวร้ายยิ่งกว่าแก้แรงเดรัจฉาน แต่ไม่ได้โดยมากขอบ สุจริตฉันคาดว่าความแตกต่างจะค่อนข้างใหญ่กว่า

python fireworks.pyทำงานด้วย:

from __future__ import print_function
import sys

total_length = total_area = failures = 0

for line in sys.stdin:
    # Read input.
    line = line.strip()
    if line == "": continue
    fws = line.split(' ')
    # The fireworks are a list of pairs of the form (<letter>, <time>).
    fws = [(fws[i], int(fws[i + 1])) for i in xrange(0, len(fws), 2)]

    # The board is a dictionary of the form <coord>: <tile>.
    # The first tile marks the "starting point" and is out-of-bounds.
    board = {(-1, 0): '*'}
    # The tip of the main "staircase" fuse.
    tip_x, tip_y = -1, 0
    tip_time = 0
    # We didn't fail. Yet...
    failed = False

    for (fw, fw_time) in fws:
        dt = fw_time - tip_time
        # Can we add the firework to the main fuse line?
        if dt > 0:
            # We can. Alternate the direction to create a "staircase" pattern.
            if board[(tip_x, tip_y)] == '-':    dx, dy = 0, 1; fuse = '|'
            else:                               dx, dy = 1, 0; fuse = '-'
            x, y = tip_x, tip_y
            tip_x += dt * dx
            tip_y += dt * dy
            tip_time += dt
        else:
            # We can't. Trace the main fuse back until we find a point where we
            # can thread, or fail if we reach the starting point.
            x, y = tip_x, tip_y
            while board[(x, y)] != '*':
                horz = board[(x, y)] == '-'
                if horz:    dx, dy = 0, 1; fuse = '|'
                else:       dx, dy = 1, 0; fuse = '-'
                if dt > 0 and (x + dx, y + dy) not in board: break
                if horz:    x -= 1
                else:       y -= 1
                dt += 1
            if board[(x, y)] == '*':
                failed = True
                break
        # Add the fuse and firework.
        for i in xrange(dt):
            x += dx; y += dy
            board[(x, y)] = fuse
        board[(x + dx, y + dy)] = fw

    # Print output.
    print(line)
    if not failed:
        max_x, max_y = (max(board, key=lambda p: p[i])[i] + 1 for i in (0, 1))
        for y in xrange(max_y):
            for x in xrange(max_x):
                print(board.get((x, y), ' '), end = "")
            print()
        length = len(board) - len(fws) - 1
        area = max_x * max_y
    else:
        print("FAILED!")
        failures += 1
        length = sum(map(lambda fw: fw[1], fws))
        area = fws[-1][1] ** 2
    print("Length: %d, Area: %d.\n" % (length, area))
    total_length += length; total_area += area

print("Total Length: %d, Total Area: %d, Failures: %d." %
        (total_length, total_area, failures))

จากความอยากรู้สิ่งนี้ใช้เวลานานแค่ไหนในการทำให้พารามิเตอร์ปัจจุบันเสร็จสมบูรณ์?
Geobits

@Geobits: มันขึ้นอยู่กับเครื่องจักรชัดและฉันไม่ได้ดูอย่างใกล้ชิดเกินไป แต่ฉันคิดว่าประมาณยี่สิบนาทีให้หรือใช้
DarwinBot
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.