เมทริกซ์คุณสมบัติ X กลับมาอีกครั้ง (หรือ Joy of X)


11

ความท้าทายนี้เป็นความท้าทายส่วนหนึ่งของอัลกอริทึมส่วนหนึ่งเป็นความท้าทายด้านการปรับให้เหมาะสมส่วนหนึ่งเป็นความท้าทายด้านโค้ดที่เร็วที่สุด

AT เมทริกซ์ที่ระบุไว้อย่างเต็มที่โดยแถวแรกของมันและคอลัมน์แรกr cแต่ละองค์ประกอบที่เหลือของเมทริกซ์เป็นเพียงสำเนาขององค์ประกอบที่เป็นเส้นทแยงมุมขึ้นและซ้าย M[i,j] = M[i-1,j-1]กล่าวคือ เราจะอนุญาตให้เมทริกซ์ T ที่ไม่ได้เป็นสแควร์ อย่างไรก็ตามเราคิดเสมอว่าจำนวนแถวไม่เกินจำนวนคอลัมน์ ตัวอย่างเช่นพิจารณาเมทริกซ์ 3 คูณ 5 ต่อไปนี้

10111
11011
11101

เราบอกว่าเมทริกซ์มีคุณสมบัติ X ถ้ามันมีคอลัมน์ที่ไม่ว่างสองชุดที่มีดัชนีไม่เหมือนกันซึ่งมีผลรวม (เวกเตอร์) เหมือนกัน ผลรวมเวกเตอร์ของคอลัมน์อย่างน้อยหนึ่งคอลัมน์เป็นเพียงการสรุปองค์ประกอบที่ชาญฉลาดของคอลัมน์ นั่นคือผลรวมของสองคอลัมน์ขึ้นไปที่มีxองค์ประกอบแต่ละรายการเป็นอีกคอลัมน์ที่มีxองค์ประกอบ ผลรวมของหนึ่งคอลัมน์เป็นคอลัมน์เล็ก ๆ น้อย ๆ

เมทริกซ์ด้านบนมีคุณสมบัติ X เล็กน้อยเนื่องจากคอลัมน์แรกและคอลัมน์สุดท้ายเหมือนกัน เมทริกซ์เอกลักษณ์ไม่เคยมีคุณสมบัติ X

หากเราเพิ่งลบคอลัมน์สุดท้ายของเมทริกซ์ด้านบนเราจะได้ตัวอย่างซึ่งไม่มีคุณสมบัติ X และจะให้คะแนน 4/3

1011
1101
1110

งาน

งานคือการเขียนรหัสเพื่อค้นหาเมทริกซ์ T คะแนนสูงสุดกับรายการไบนารีและที่ ไม่มีคุณสมบัติ X เพื่อความชัดเจนเมทริกซ์ที่มีรายการไบนารีมีคุณสมบัติที่แต่ละรายการของรายการนั้นเป็น 0 หรือ 1

คะแนน

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

Tie Breaker

หากคำตอบสองข้อมีคะแนนเท่ากันคำตอบที่ชนะจะได้รับก่อน

ในกรณีที่ไม่น่าเป็นไปได้มากที่ใครบางคนพบวิธีการที่จะได้รับคะแนนไม่ จำกัด หลักฐานที่ถูกต้องแรกของการแก้ปัญหาดังกล่าวจะได้รับการยอมรับ ในกรณีที่ไม่น่าเป็นไปได้มากขึ้นที่คุณสามารถหาข้อพิสูจน์ของการหาค่าเหมาะที่สุดของเมทริกซ์ จำกัด แน่นอนว่าฉันจะได้รับรางวัลเช่นกัน

เปรย

คำตอบทั้งหมดที่ค้นหาเมทริกซ์การให้คะแนนที่สูงที่สุดโดยไม่มีคุณสมบัติ Xนั้นถูกต้องที่นี่ แต่ก็ไม่เหมาะสม มีเมทริกซ์ T ที่ไม่มีคุณสมบัติ X ซึ่งไม่ใช่วัฏจักร

ตัวอย่างเช่นมีเมทริกซ์ 7 คูณ 12 โดยไม่มีคุณสมบัติ X แต่ไม่มีเมทริกซ์แบบวนรอบนั้น

21/11 จะเอาชนะคำตอบปัจจุบันทั้งหมดจากสิ่งนี้และความท้าทายที่ผ่านมา

ภาษาและห้องสมุด

คุณสามารถใช้ภาษาใดก็ได้ที่มีคอมไพเลอร์ / ล่าม / อื่น ๆ สำหรับ Linux และไลบรารี่ใด ๆ ที่มีให้ใช้งานบน Linux ได้อย่างอิสระ

โบนัสคำตอบแรกที่มีคะแนนมากกว่า 2 จะได้รับรางวัล200 แต้มทันที ตอนนี้ Ton Hospel ประสบความสำเร็จในสิ่งนี้!


กระดานผู้นำปัจจุบัน

  • C ++ คะแนน 31/15 โดย Ton Hospel
  • ชวา คะแนน 36/19 โดย Peter Taylor
  • Haskell คะแนน 14/8 โดย alexander-brett

จาก "คอลัมน์สองชุดที่ไม่ว่างเปล่าที่มีดัชนีไม่เหมือนกัน" คุณหมายถึงคอลัมน์สองชุดที่ไม่เชื่อมกันหรือ หรือหากต้องการใช้ถ้อยคำนี้อีกครั้ง {1, 3}, {1, 5} เป็นคอลัมน์ย่อยสองคอลัมน์ที่ถูกต้องหรือไม่
pawel.boczarski

@ pawel.boczarski ไม่ไม่แยกจากกัน เพียงไม่เหมือนกัน ดังนั้น {1, 3}, {1, 5} จึงถูกต้อง

ตกลง. แล้ว M [i, 1] - คืออะไร "ยืม" จากคอลัมน์สุดท้ายของ M [i-1] (ศูนย์ไม่ใช่ดัชนีคอลัมน์เมทริกซ์ที่ถูกต้อง) และที่จริงนี่คือ "ขึ้นและซ้าย" มากกว่า "ขึ้นและลง"
pawel.boczarski

@ pawel.boczarski "ถูกต้อง" เป็นตัวพิมพ์ผิด ขอบคุณ แถวและคอลัมน์แรกสามารถตั้งค่าเป็นอะไรก็ได้ที่คุณต้องการ พวกเขากำหนดเมทริกซ์ที่เหลือทั้งหมด นั่นตอบคำถามของคุณหรือไม่

โอเคเข้าใจแล้ว. มันเป็นความผิดของฉันที่ไม่ได้อ่านอย่างละเอียดว่ามีการกำหนดคอลัมน์แรก
pawel.boczarski

คำตอบ:


6

C ++, คะแนน23/12 25/13 27/14 28/14 31/15

ในที่สุดผลลัพธ์กับอัตราส่วน> 2:

rows=15,cols=31
1 1 0 0 1 0 0 0 1 1 1 1 0 1 0 1 1 0 0 1 0 0 0 1 1 1 1 0 1 1 0 
1 1 1 0 0 1 0 0 0 1 1 1 1 0 1 0 1 1 0 0 1 0 0 0 1 1 1 1 0 1 1 
1 1 1 1 0 0 1 0 0 0 1 1 1 1 0 1 0 1 1 0 0 1 0 0 0 1 1 1 1 0 1 
1 1 1 1 1 0 0 1 0 0 0 1 1 1 1 0 1 0 1 1 0 0 1 0 0 0 1 1 1 1 0 
1 1 1 1 1 1 0 0 1 0 0 0 1 1 1 1 0 1 0 1 1 0 0 1 0 0 0 1 1 1 1 
0 1 1 1 1 1 1 0 0 1 0 0 0 1 1 1 1 0 1 0 1 1 0 0 1 0 0 0 1 1 1 
0 0 1 1 1 1 1 1 0 0 1 0 0 0 1 1 1 1 0 1 0 1 1 0 0 1 0 0 0 1 1 
1 0 0 1 1 1 1 1 1 0 0 1 0 0 0 1 1 1 1 0 1 0 1 1 0 0 1 0 0 0 1 
0 1 0 0 1 1 1 1 1 1 0 0 1 0 0 0 1 1 1 1 0 1 0 1 1 0 0 1 0 0 0 
0 0 1 0 0 1 1 1 1 1 1 0 0 1 0 0 0 1 1 1 1 0 1 0 1 1 0 0 1 0 0 
0 0 0 1 0 0 1 1 1 1 1 1 0 0 1 0 0 0 1 1 1 1 0 1 0 1 1 0 0 1 0 
1 0 0 0 1 0 0 1 1 1 1 1 1 0 0 1 0 0 0 1 1 1 1 0 1 0 1 1 0 0 1 
0 1 0 0 0 1 0 0 1 1 1 1 1 1 0 0 1 0 0 0 1 1 1 1 0 1 0 1 1 0 0 
0 0 1 0 0 0 1 0 0 1 1 1 1 1 1 0 0 1 0 0 0 1 1 1 1 0 1 0 1 1 0 
1 0 0 1 0 0 0 1 0 0 1 1 1 1 1 1 0 0 1 0 0 0 1 1 1 1 0 1 0 1 1 

ฉันสำรวจ 1 ถึง 14 แถวอย่างสมบูรณ์ 15 จะใช้เวลานานเกินไปในการสำรวจอย่างสมบูรณ์ ผลลัพธ์ที่ได้คือ:

1/1   = 1
2/2   = 1
4/3   = 1.333
5/4   = 1.25
7/5   = 1.4
9/6   = 1.5
12/7  = 1.714
14/8  = 1.75
16/9  = 1.778
18/10 = 1.8
20/11 = 1.818
23/12 = 1.917
25/13 = 1.923
28/14 = 2

รหัสที่ระบุด้านล่างนี้เป็นรุ่นที่เก่ากว่าของโปรแกรม รุ่นใหม่ล่าสุดที่https://github.com/thospel/personal-propertyX

/*
  Compile using something like:
    g++ -Wall -O3 -march=native -fstrict-aliasing -std=c++11 -g propertyX.cpp -lpthread -o propertyX
*/
#include <cstdint>
#include <climits>
#include <ctgmath>
#include <iostream>
#include <vector>
#include <array>
#include <chrono>
#include <mutex>
#include <atomic>
#include <thread>

using namespace std;

const int ELEMENTS = 2;

using uint    = unsigned int;
using Element = uint64_t;
using Column  = array<Element, ELEMENTS>;
using Set     = vector<Column>;
using Sum     = uint8_t;
using Index   = uint32_t;
using sec = chrono::seconds;

int const PERIOD = 5*60;
int const MAX_ROWS = 54;
int const COL_FACTOR = (MAX_ROWS+1) | 1;                // 55
int const ROW_ZERO   = COL_FACTOR/2;                    // 27
int const ROWS_PER_ELEMENT = CHAR_BIT * sizeof(Element) / log2(COL_FACTOR); //11
Element constexpr ELEMENT_FILL(Element v = ROW_ZERO, int n = ROWS_PER_ELEMENT) {
    return n ? ELEMENT_FILL(v, n-1) * COL_FACTOR + v : 0;
}
Element constexpr POWN(Element v, int n) {
    return n ? POWN(v, n-1)*v : 1;
}
Element const ELEMENT_TOP = POWN(COL_FACTOR, ROWS_PER_ELEMENT -1);
int const MAX_COLS = ROWS_PER_ELEMENT * ELEMENTS;       // 22

atomic<Index> col_next;
atomic<uint>  period;
chrono::steady_clock::time_point start;
mutex period_mutex;

uint ratio_row;
uint ratio_col;
mutex ratio_mutex;

auto const nr_threads = thread::hardware_concurrency();
// auto const nr_threads = 1;

struct State {
    State(uint cols);
    void process(Index i);
    void extend(uint row);
    void print(uint rows);
    Index nr_columns() const { return static_cast<Index>(1) << cols_; }

    Column last_;
    Element top_;
    int top_offset_;
    uint ratio_row_ = 0;
    uint ratio_col_ = 1;
    uint cols_;
    array<Sum, MAX_ROWS + MAX_COLS -1> side;
    vector<Set> sets;
};

ostream& operator<<(ostream& os, Column const& column) {
    for (int i=0; i<ELEMENTS; ++i) {
        auto v = column[i];
        for (int j=0; j<ROWS_PER_ELEMENT; ++j) {
            auto bit = v / ELEMENT_TOP;
            cout << " " << bit;
            v -= bit * ELEMENT_TOP;
            v *= COL_FACTOR;
        }
    }
    return os;
}

State::State(uint cols) : cols_{cols} {
    sets.resize(MAX_ROWS+2);
    for (int i=0; i<2; ++i) {
        sets[i].resize(2);
        for (int j=0; j < ELEMENTS; ++j) {
            sets[i][0][j] =  ELEMENT_FILL();
            sets[i][1][j] =  static_cast<Element>(-1) - ELEMENT_FILL(1);
        }
    }
    top_ = POWN(COL_FACTOR, (cols_-1) % ROWS_PER_ELEMENT);
    top_offset_ = ELEMENTS - 1 - (cols_-1) / ROWS_PER_ELEMENT;
}

void State::print(uint rows) {
    for (auto c=0U; c<cols_;c++) {
        for (auto r=0U; r<rows;r++) {
            cout << static_cast<int>(side[cols_-c+r-1]) << " ";
        }
        cout << "\n";
    }
    cout << "----------" << endl;
}

void check(uint cols, uint t) {
    State state(cols);

    Index nr_columns = state.nr_columns();
    while (1) {
        Index col = col_next++;
        if (col >= nr_columns) break;
        state.process(col);

        auto now = chrono::steady_clock::now();
        auto elapsed = chrono::duration_cast<sec>(now-start).count();
        if (elapsed >= period) {
            lock_guard<mutex> lock{period_mutex};
            if (elapsed >= period) {
                cout << "col=" << col << "/" << nr_columns << " (" << 100.*col/nr_columns << "% " << elapsed << " s)" << endl;
                period = (elapsed/PERIOD+1)*PERIOD;
            }
        }
    }
}

void State::process(Index col) {
    last_.fill(0);
    for (uint i=0; i<cols_; ++i) {
        Element bit = col >> i & 1;
        side[i] = bit;
        Element carry = 0;
        for (int j=0; j<ELEMENTS; ++j) {
            auto c = last_[j] % COL_FACTOR;
            last_[j] = last_[j] / COL_FACTOR + carry * ELEMENT_TOP;
            if (j == top_offset_ && bit) last_[j] += top_;
            carry = c;
        }
    }
    // cout << "col=" << col << ", value=" << last_ << "\n";
    extend(0);
}

void State::extend(uint row) {
    // cout << "Extend row " << row << " " << static_cast<int>(side[cols_+row-1]) << "\n";
    if (row >= MAX_ROWS) throw(range_error("row out of range"));

    // Execute subset sum. The new column is added to set {from} giving {to}
    // {sum} is the other set.
    auto const& set_from = sets[row];
    auto const& set_sum  = sets[row + 1];
    auto      & set_to   = sets[row + 2];
    if (set_to.size() == 0) {
        auto size = 3 * set_from.size() - 2;
        set_to.resize(size);
        for (int j=0; j<ELEMENTS; ++j)
            set_to[size-1][j] = static_cast<Element>(-1) - ELEMENT_FILL(1);
    }

    // Merge sort {set_from - last_} , {set_from} and {set_from + last_}
    auto ptr_sum    = &set_sum[1][0];
    auto ptr_low    = &set_from[0][0];
    auto ptr_middle = &set_from[0][0];
    auto ptr_high   = &set_from[0][0];
    Column col_low, col_high;
    for (int j=0; j<ELEMENTS; ++j) {
        col_low   [j] = *ptr_low++  - last_[j];
        col_high  [j] = *ptr_high++ + last_[j];
    }

    auto ptr_end = &set_to[set_to.size()-1][0];
    auto ptr_to  = &set_to[0][0];
    while (ptr_to < ptr_end) {
        for (int j=0; j<ELEMENTS; ++j) {
            if (col_low[j] < ptr_middle[j]) goto LOW;
            if (col_low[j] > ptr_middle[j]) goto MIDDLE;
        }
        // low == middle
        // cout << "low == middle\n";
        return;

      LOW:
        // cout << "LOW\n";
        for (int j=0; j<ELEMENTS; ++j) {
            if (col_low[j] < col_high[j]) goto LOW0;
            if (col_low[j] > col_high[j]) goto HIGH0;
        }
        // low == high
        // cout << "low == high\n";
        return;

      MIDDLE:
        // cout << "MIDDLE\n";
        for (int j=0; j<ELEMENTS; ++j) {
            if (ptr_middle[j] < col_high[j]) goto MIDDLE0;
            if (ptr_middle[j] > col_high[j]) goto HIGH0;
        }
        // middle == high
        // cout << "middle == high\n";
        return;

      LOW0:
        // cout << "LOW0\n";
        for (int j=0; j<ELEMENTS; ++j) {
            *ptr_to++  = col_low[j];
            col_low[j] = *ptr_low++ - last_[j];
        }
        goto SUM;

      MIDDLE0:
        // cout << "MIDDLE0\n";
        for (int j=0; j<ELEMENTS; ++j)
            *ptr_to++ = *ptr_middle++;
        goto SUM;

      HIGH0:
        // cout << "HIGH0\n";
        for (int j=0; j<ELEMENTS; ++j) {
            *ptr_to++ = col_high[j];
            col_high[j] = *ptr_high++ + last_[j];
        }
        goto SUM;
      SUM:
        for (int j=-ELEMENTS; j<0; ++j) {
            if (ptr_to[j] > ptr_sum[j]) {
                ptr_sum += ELEMENTS;
                goto SUM;
            }
            if (ptr_to[j] < ptr_sum[j]) goto DONE;
        }
        // sum == to
        for (int j=-ELEMENTS; j<0; ++j)
            if (ptr_to[j] != ELEMENT_FILL()) {
                // sum == to and to != 0
                // cout << "sum == to\n";
                // cout << set_sum[(ptr_sum - &set_sum[0][0])/ELEMENTS-1] << "\n";
                return;
            }
      DONE:;
    }
    // cout << "Wee\n";
    auto row1 = row+1;
    if (0)
        for (uint i=0; i<row1+2; ++i) {
            cout << "Set " << i << "\n";
            auto& set = sets[i];
            for (auto& column: set)
                cout << column << "\n";
        }

    if (row1 * ratio_col_ > ratio_row_ * cols_) {
        ratio_row_ = row1;
        ratio_col_ = cols_;
        lock_guard<mutex> lock{ratio_mutex};

        if (ratio_row_ * ratio_col > ratio_row * ratio_col_) {

            auto now = chrono::steady_clock::now();
            auto elapsed = chrono::duration_cast<sec>(now-start).count();
            cout << "cols=" << cols_ << ",rows=" << row1 << " (" << elapsed << " s)\n";
            print(row1);
            ratio_row = ratio_row_;
            ratio_col = ratio_col_;
        }
    }

    auto last = last_;

    Element carry = 0;
    for (int j=0; j<ELEMENTS; ++j) {
        auto c = last_[j] % COL_FACTOR;
        last_[j] = last_[j] / COL_FACTOR + carry * ELEMENT_TOP;
        carry = c;
    }

    side[cols_+row] = 0;
    extend(row1);

    last_[top_offset_] += top_;
    side[cols_+row] = 1;
    extend(row1);

    last_ = last;
}

void my_main(int argc, char** argv) {
    if (!col_next.is_lock_free()) cout << "col_next is not lock free\n";
    if (!period.  is_lock_free()) cout << "period is not lock free\n";

    int min_col = 2;
    int max_col = MAX_COLS;
    if (argc > 1) {
        min_col = atoi(argv[1]);
        if (min_col < 2)
            throw(range_error("Column must be >= 2"));
        if (min_col > MAX_COLS)
            throw(range_error("Column must be <= " + to_string(MAX_COLS)));
    }
    if (argc > 2) {
        max_col = atoi(argv[2]);
        if (max_col < min_col)
            throw(range_error("Column must be >= " + to_string(min_col)));
        if (max_col > MAX_COLS)
            throw(range_error("Column must be <= " + to_string(MAX_COLS)));
    }

    for (int cols = min_col; cols <= max_col; ++cols) {
        cout << "Trying " << cols << " columns" << endl;
        ratio_row = 0;
        ratio_col = 1;
        col_next = 0;
        period = PERIOD;
        start = chrono::steady_clock::now();
        vector<thread> threads;
        for (auto t = 1U; t < nr_threads; t++)
            threads.emplace_back(check, cols, t);
        check(cols, 0);
        for (auto& thread: threads)
            thread.join();
    }
}

int main(int argc, char** argv) {
    try {
        my_main(argc, argv);
    } catch(exception& e) {
        cerr << "Error: " << e.what() << endl;
        exit(EXIT_FAILURE);
    }
    exit(EXIT_SUCCESS);
}

มันเยี่ยมมาก ความลึกลับที่ยิ่งใหญ่คือถ้าคุณได้คะแนน 2

ฉันคิดว่า 28/14 น่าจะมีอยู่จริงซึ่งน่าตื่นเต้นจริงๆ แต่มันเพิ่งจะเอื้อมถึง?

n = 14 จะใช้เวลาประมาณ 200 วันกับรหัสปัจจุบันของฉันใน CPU 8-core ของฉัน รหัสอาจถูกเร่งความเร็วขึ้น 30% หรือมากกว่านั้น หลังจากนั้นฉันก็หมดความคิด และการคาดการณ์ของคุณดูเหมือนจะค่อนข้างมองโลกในแง่นะ ...
Ton Hospel

ฉันคิดว่าเมทริกซ์ circulant 50 คูณ 25 กับแถวแรก 01011011100010111101000001100111110011010100011010 อาจทำงานได้ สิ่งนี้ถูกค้นพบโดยการเพิ่มประสิทธิภาพการแก้ปัญหาซึ่งอาจเป็นประโยชน์

140 ชั่วโมงสำหรับการครอบคลุมอย่างหมดจดจาก n = 14 เป็นไปอย่างรวดเร็วอย่างน่าประทับใจฉันต้องพูด

2

Haskell 14/8 = 1.75

1 1 0 0 0 1 0 1 1 0 1 1 0 0
1 1 1 0 0 0 1 0 1 1 0 1 1 0
0 1 1 1 0 0 0 1 0 1 1 0 1 1
1 0 1 1 1 0 0 0 1 0 1 1 0 1
0 1 0 1 1 1 0 0 0 1 0 1 1 0
0 0 1 0 1 1 1 0 0 0 1 0 1 1
0 0 0 1 0 1 1 1 0 0 0 1 0 1
0 0 0 0 1 0 1 1 1 0 0 0 1 0

ก่อนหน้านี้ 9/6 = 1.5

1 0 1 0 1 1 0 0 1
1 1 0 1 0 1 1 0 0
1 1 1 0 1 0 1 1 0
1 1 1 1 0 1 0 1 1
1 1 1 1 1 0 1 0 1
1 1 1 1 1 1 0 1 0

ฉันเขียนสิ่งนี้จากนั้นดูคำตอบของคำถามอื่นและรู้สึกท้อแท้

import Data.List
import Data.Hashable
import Control.Monad
import Control.Parallel.Strategies
import Control.Parallel
import qualified Data.HashSet as S

matrix§indices = [ matrix!!i | i<-indices ]

powerset :: [a] -> [[a]]
powerset = filterM (const [True, False])

hashNub :: (Hashable a, Eq a) => [a] -> [a]
hashNub l = go S.empty l
    where
      go _ []     = []
      go s (x:xs) = if x `S.member` s
        then go s xs
        else x : go (S.insert x s) xs

getMatrix :: Int -> Int -> [Int] -> [[Int]]
getMatrix width height vector = [ vector § [x..x+width-1] | x<-[0..height-1] ]

hasDuplicate :: (Hashable a, Eq a) => [a] -> Bool
hasDuplicate m = go S.empty m
    where
        go _ [] = False
        go s (x:xs) = if x `S.member` s
            then True
            else go (S.insert x s) xs

hasProperty :: [[Int]] -> Bool
hasProperty matrix =
    let
        base = replicate (length (matrix !! 0)) 0::[Int]
    in
        if elem base matrix then
            False
        else
            if hasDuplicate matrix then
                False
            else
                if hasDuplicate (map (foldl (zipWith (+)) base) (powerset matrix)) then
                    False
                else
                    True


pmap = parMap rseq

matricesWithProperty :: Int -> Int -> [[[Int]]]
matricesWithProperty n m =
    let
        base = replicate n 0::[Int]
    in
    filter (hasProperty) $
    map (getMatrix n m) $
    sequence [ [0,1] | x<-[0..n+m-1] ]

firstMatrixWithProperty :: Int -> Int -> [[Int]]
firstMatrixWithProperty n m = head $ matricesWithProperty n m

main = mapM (putStrLn. show) $ map (firstMatrixWithProperty 8) [1..]

ขอบคุณ! คำตอบของ Haskell ยินดีต้อนรับเสมอ ฉันคิดว่ากรณีที่น่าสนใจแรกคือ 12/7 คุณจะได้รับที่?

ผมกำลังทำงานบนแล็ปท็อปแบบ dual-core ปี 2009 จึงไม่มี :) ผมจะพยายามอีกครั้งบนเครื่องได้เร็วขึ้นแม้ว่า
อเล็กซานเด-Brett

ดีมาก. ฉันเพิ่งเพิ่มความคิดเห็นที่ 21/11 จะเอาชนะคำตอบก่อนหน้านี้ทั้งหมด

คุณช่วยอธิบายได้ว่าโค้ดของคุณออกมาเป็นอะไรกันบ้าง?

ในmainจำนวน (ในกรณีนี้8) คือความสูงของเมทริกซ์และ iterates [1..]โปรแกรมผ่านความกว้าง สำหรับการรวมกันของความสูง / ความกว้างแต่ละรายการจะพิมพ์อาร์เรย์ของคอลัมน์ของเมทริกซ์ที่ถูกต้อง
alexander-brett

1

ต่อไปนี้เป็นคำตอบที่ใช้งานได้ดีกว่าหน่วยความจำ Haskell น่าเสียดายที่คอมพิวเตอร์ของฉันยังช้าเกินไปที่จะประสบความสำเร็จดีกว่า 14/8 ในระยะเวลาที่เหมาะสม

ลองรวบรวมด้วยgcc -std=c99 -O2 -fopenmp -o matrices.exe matrices.cและทำงานด้วยmatrices.exe width heightหรือคล้ายกัน เอาต์พุตเป็นจำนวนเต็มบิตที่เป็นพื้นฐานสำหรับเมทริกซ์ที่เป็นปัญหาตัวอย่างเช่น

$ matrices.exe 8 14
...
valid i: 1650223

จากนั้น1650223 = 0b110010010111000101111เมทริกซ์ที่มีปัญหาคือ:

0 0 1 1 1 0 1 0 0 1 0 0 1 1
0 ...
1 ...
0
1
1
1
1

หากใครบางคนที่มี 8 คอร์และเวลาอยู่ในมือของพวกเขาต้องการที่จะทำงานในขณะนี้ฉันคิดว่าบางสิ่งที่ดีอาจส่งผล :)


#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

/*
 * BEGIN WIKIPEDIA CODE
 */
const long long m1  = 0x5555555555555555; //binary: 0101...
const long long m2  = 0x3333333333333333; //binary: 00110011..
const long long m4  = 0x0f0f0f0f0f0f0f0f; //binary:  4 zeros,  4 ones ...
const long long m8  = 0x00ff00ff00ff00ff; //binary:  8 zeros,  8 ones ...
const long long m16 = 0x0000ffff0000ffff; //binary: 16 zeros, 16 ones ...
const long long m32 = 0x00000000ffffffff; //binary: 32 zeros, 32 ones
const long long hff = 0xffffffffffffffff; //binary: all ones
const long long h01 = 0x0101010101010101; //the sum of 256 to the power of 0,1,2,3...
//This uses fewer arithmetic operations than any other known
//implementation on machines with fast multiplication.
//It uses 12 arithmetic operations, one of which is a multiply.
long long hamming(long long x) {
    x -= (x >> 1) & m1;             //put count of each 2 bits into those 2 bits
    x = (x & m2) + ((x >> 2) & m2); //put count of each 4 bits into those 4 bits
    x = (x + (x >> 4)) & m4;        //put count of each 8 bits into those 8 bits
    return (x * h01)>>56;  //returns left 8 bits of x + (x<<8) + (x<<16) + (x<<24) + ...
}
/*
 * END WIKIPEDIA CODE
 */

int main ( int argc, char *argv[] ) {
    int height;
    int width;

    sscanf(argv[1], "%d", &height);
    sscanf(argv[2], "%d", &width);

    #pragma omp parallel for
    for (
        /*
         * We know that there are 2^(h+w-1) T-matrices, defined by the entries
         * in the first row and first column. We'll let the long long i
         * represent these entries, with 1s represented by set bits.
         *
         * The first (0) and last (1) matrix we will ignore.
         */
        long long i = 1;
        i < (1 << (height+width-1))-1;
        i++
    ) {
        // Flag for keeping track as we go along.
        int isvalid = 1;

        /*
         * Start by representing the matrix as an array of columns, with each
         * non-zero matrix entry as a bit. This allows us to construct them and
         * check equality very quickly.
         */
        long *cols = malloc(sizeof(long)*width);
        long colmask = (1 << height)-1;
        for (int j = 0; j < width; j++) {
            cols[j] = (i >> j) & colmask;
            if (cols[j] == 0) {
                //check no zero rows
                isvalid = 0;
            } else {
                //check no duplicate rows
                for (int k = 0; k < j; k++) {
                    if (cols[j] == cols[k]) {
                        isvalid = 0;
                    }
                }
            }
        }

        if (isvalid == 1) {
            /*
             * We'll also represent the matrix as an array of rows, in a
             * similar manner.
             */
            long *rows = malloc(sizeof(long)*height);
            long rowmask = (1 << width)-1;
            for (int j = 0; j < height; j++) {
                rows[j] = (i >> j) & rowmask;
            }

            int *sums[(1 << width)];
            for (long j = 0; j < 1<<width; j++) {
                sums[j] = (int*)malloc(sizeof(int)*height);
            }

            for (
                /*
                 * The powerset of columns has size 2^width. Again with the
                 * long; this time each bit represents whether the
                 * corresponding row is a member of the subset. The nice thing
                 * about this is we can xor the permutation with each row,
                 * then take the hamming number of the resulting number to get
                 * the sum.
                 */
                long permutation = 1;
                (isvalid == 1) && (permutation < (1 << width)-1);
                permutation ++
            ) {
                for (int j = 0; j < height; j++) {
                    sums[permutation][j] = hamming( rows[j] & permutation);
                }
                for (int j = permutation-1; (isvalid == 1) && (j > -1); j--) {
                    if (memcmp(sums[j], sums[permutation], sizeof(int)*height) == 0) {
                        isvalid = 0;
                    }
                }
            }

            for (long j = 0; j < 1<<width; j++) {
                free(sums[j]);
            }

            free(rows);

        }

        if (isvalid == 1) {
            printf ("valid i: %ld\n", i);
        }

        free(cols);
    }

    return 0;
}

ฉันได้รับ alexander-brett.c: ในฟังก์ชั่น 'main': alexander-brett.c: 107: 21: คำเตือน: การประกาศโดยนัยของฟังก์ชัน 'memcmp' [-Wimplicit-function-declaration] if (memcmp (sums [j], ผลรวม [การเปลี่ยนแปลง], ขนาดของ (int) * สูง) == 0) {^ alexander-brett.c: 122: 13: คำเตือน: รูปแบบ '% ld' คาดว่าจะมีอาร์กิวเมนต์ประเภท 'long int' แต่อาร์กิวเมนต์ 2 มีชนิด ' long long int '[-Wformat =] printf ("valid i:% ld \ n", i);

/alexander-brett 8 14 ใช้เวลานานเท่าไหร่?

สวัสดี Lembik, 8 14 ได้ 5 คำตอบในหนึ่งชั่วโมงสำหรับฉันบนเครื่อง quad core ฉันจัดการเพื่อคอมไพล์กับส่วนหัวเหล่านั้นบน windows มันคงจะแปลกถ้า memcmp หายไป ...
alexander-brett


ฉันพยายามรหัสของคุณด้วย 7 12 valid i: 7481และหนึ่งในคำตอบมันจะออกผลลัพธ์คือ ใน python bin (7481) คือ 0b1110100111001 ซึ่งไม่ยาวพอ ความคิดใด ๆ ที่เกิดขึ้น?
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.