छड़ की एक श्रृंखला के साथ Polyominoes का गठन


20

पृष्ठभूमि

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

आइए एक उदाहरण देखें। एक विशेष श्रृंखला पर विचार करें जिसमें लंबाई 1 और 2 की 8 छड़ें होती हैं, जिसे हम इस रूप में दर्शा सकते हैं [1, 1, 2, 2, 1, 1, 2, 2]। रोटेशन और अनुवादों तक, केवल 8 संभव पॉलीओमीनो हैं (हम विभिन्न प्रतिबिंबों की गणना करते हैं):

यहां छवि विवरण दर्ज करें

यह पहली छड़ गहरे नीले रंग की होती है, और फिर हम बहुभुज को काउंटर-क्लॉकवाइज अर्थों में पार कर लेते हैं।

रोटेशन की भावना उपरोक्त उदाहरण में परिणाम को प्रभावित नहीं करती है। लेकिन आइए एक और श्रृंखला पर विचार करें [3, 1, 1, 1, 2, 1, 1], जो निम्नलिखित 3 पॉलीओमीनो की पैदावार देती है:

यहां छवि विवरण दर्ज करें

ध्यान दें कि हम अंतिम पॉलोमिनो का प्रतिबिंब शामिल नहीं करते हैं, क्योंकि इसके लिए दक्षिणावर्त ट्रैवर्सल की आवश्यकता होगी।

यदि हमारे पास समान लंबाई की अधिक लचीली श्रृंखला होती, तो [1, 1, 1, 1, 1, 1, 1, 1, 1, 1], हम वास्तव में कुछ अन्य पॉलीओनोइनो के बीच दोनों प्रतिबिंबों को बनाने में सक्षम होते, कुल 9:

यहां छवि विवरण दर्ज करें

चुनौती

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

कृपया एक पूरा कार्यक्रम लिखें और कमांड लाइन से अपना कोड संकलित (यदि लागू हो) और अपना कोड शामिल करें। कृपया अपनी भाषा के लिए एक मुफ्त संकलक / दुभाषिया का लिंक भी शामिल करें।

आपके प्रोग्राम को STDIN से इनपुट पढ़ना चाहिए। पहली पंक्ति में एक पूर्णांक M होगा । अगली एम लाइनें परीक्षण के मामले होंगे, जिनमें से प्रत्येक रॉड की लंबाई वाली अंतरिक्ष-पृथक सूची होगी। आपके प्रोग्राम को M लाइनों को STDOUT में प्रिंट करना चाहिए , जिनमें से प्रत्येक में एक पूर्णांक होता है - अलग-अलग पॉलीओमीनो की संख्या जो बन सकती है।

आपको केवल एक ही धागे का उपयोग करना चाहिए।

आपके प्रोग्राम को किसी भी समय 1 जीबी से अधिक मेमोरी का उपयोग नहीं करना चाहिए। (यह पूरी तरह से सख्त सीमा नहीं है, लेकिन मैं आपके निष्पादन योग्य मेमोरी उपयोग की निगरानी करूंगा, और किसी भी प्रक्रिया को मार सकता हूं जो लगातार 1 जीबी से अधिक का उपयोग करता है, या इसके ऊपर काफी स्पाइक्स होता है।)

पूर्व-संगणना की अत्यधिक मात्रा को रोकने के लिए, आपका कोड 20,000 बाइट्स से अधिक नहीं होना चाहिए, और आपको किसी भी फाइल को नहीं पढ़ना चाहिए।

आपको चुने गए विशिष्ट परीक्षण मामलों की ओर भी अनुकूलन नहीं करना चाहिए (जैसे कि उनके परिणामों को हार्डकोड करके)। यदि मुझे संदेह है कि आप करते हैं, तो मुझे नए बेंचमार्क सेट जनरेट करने का अधिकार सुरक्षित है। परीक्षण सेट यादृच्छिक हैं, इसलिए उन पर आपके कार्यक्रम का प्रदर्शन मनमाना इनपुट पर इसके प्रदर्शन के लिए प्रतिनिधि होना चाहिए। एकमात्र धारणा जिसे आप बनाने की अनुमति देते हैं, वह यह है कि रॉड की लंबाई का योग सम है।

स्कोरिंग

मैंने एन = 10, 11, ..., 20 छड़ों की श्रृंखला के लिए बेंचमार्क सेट प्रदान किए हैं । प्रत्येक परीक्षण सेट में 1 और 4 के बीच की लंबाई के साथ 50 यादृच्छिक श्रृंखलाएं होती हैं।

आपका प्राथमिक स्कोर सबसे बड़ा एन है , जिसके लिए आपका कार्यक्रम 5 मिनट के भीतर (मेरी मशीन पर, विंडोज 8 के तहत) पूरे परीक्षण सेट को पूरा करता है। टाई ब्रेकर उस परीक्षण सेट पर आपके कार्यक्रम द्वारा लिया गया वास्तविक समय होगा।

अगर कोई सबसे बड़ा परीक्षण सेट मारता है, तो मैं बड़े लोगों को जोड़ता रहूंगा।

परीक्षण के मामलों

अपने कार्यान्वयन की शुद्धता की जांच करने के लिए आप निम्नलिखित परीक्षण मामलों का उपयोग कर सकते हैं।

Input                            Output

1 1                              0
1 1 1 1                          1
1 1 1 1 1 1                      1
1 1 1 1 1 1 1 1                  3
1 1 1 1 1 1 1 1 1 1              9
1 1 1 1 1 1 1 1 1 1 1 1          36
1 1 1 1 1 1 1 1 1 1 1 1 1 1      157
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1  758
1 1 2 2 1 1 2 2                  8
1 1 2 2 1 1 2 2 1 1              23
1 1 2 2 1 1 2 2 1 1 2 2          69
1 2 1 2 1 2 1 2                  3
1 2 1 2 1 2 1 2 1 2 1 2          37
1 2 3 2 1 2 3 2                  5
1 2 3 2 1 2 3 2 1 2 3 2          23
3 1 1 1 2 1 1                    3
1 2 3 4 5 6 7                    1
1 2 3 4 5 6 7 8                  3
1 2 3 4 5 6 7 8 9 10 11          5
2 1 5 3 3 2 3 3                  4
4 1 6 5 6 3 1 4                  2
3 5 3 5 1 4 1 1 3                5
1 4 3 2 2 5 5 4 6                4
4 1 3 2 1 2 3 3 1 4              18
1 1 1 1 1 2 3 3 2 1              24
3 1 4 1 2 2 1 1 2 4 1 2          107
2 4 2 4 2 2 3 4 2 4 2 3          114

आप यहाँ इन के साथ एक इनपुट फ़ाइल पाते हैं

लीडरबोर्ड

   User          Language       Max N      Time taken (MM:SS:mmm)

1. feersum       C++ 11         19         3:07:430

2. Sp3000        Python 3       18         2:30:181

"छेद-मुक्त" सतही लगता है। एक सन्निहित श्रृंखला पहली जगह में छेद वाले पॉलोमिनोइन का उत्पादन नहीं कर सकती है।
शुक्राणु

क्या मल्टी-थ्रेडिंग की अनुमति है? और अगर धागे विभिन्न प्रक्रियाओं में हैं, तो क्या प्रत्येक को 1 जीबी का उपयोग करने के लिए मिलता है? : P
feersum

@ शेपर यह तब हो सकता है जब परिधि खुद को एक कोने में छू ले। उदाहरण के लिए, यहां नंबर 81 देखें। वह एक नहीं गिना जाना चाहिए।
मार्टिन एंडर

@ Faersum सादगी के लिए, मैं मल्टी-थ्रेडिंग के लिए नहीं (और चुनौती को संपादित करूँगा) कहने जा रहा हूँ।
मार्टिन एंडर

1
@PeterKagey क्या आपने यह टिप्पणी गलत चुनौती पर पोस्ट की है? लगता है इस पर चले जाना चाहिए था ।
मार्टिन एंडर

जवाबों:


5

सी ++ 11

अपडेट्स: पहली पंक्ति को जोड़ा गया है cजो अगर जल्दी निकल जाता है तो दूरी मूल से बहुत दूर है (जो कि चर का पूरा उद्देश्य था rlen, लेकिन मैं इसे पहले संस्करण में लिखना भूल गया)। मैंने इसे बहुत कम मेमोरी का उपयोग करने के लिए बदल दिया, लेकिन समय की कीमत पर। अब यह मेरे लिए सिर्फ 5 मिनट के भीतर एन = 20 को हल करता है।

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <map>
#include <ctime>

#define M std::map
#define MS 999
#define l (xM*2+1)

#define KITTENS(A,B)A##B
#define CATS(A,B)KITTENS(A,B)
#define LBL CATS(LBL,__LINE__)
#define unt unsigned
#define SU sizeof(unt)
#define SUB (SU*8)
#define newa (nb^SZ||fail("blob"),nb+++blob)

#define D

struct vec {int x, y;};


unt s[MS*2];
int xM, sl[MS];
vec X[MS];

struct a;
struct a  { M<unt,unt>v;};

#define SZ ((1<<29)/sizeof(a))
a*blob;
unt nb;


int fail(const char*msg)
{
    printf("failed:%s", msg);
    exit(1);
    return 1;
}

struct
{
    unt*m;
    bool operator()(int x, int y) { return m[(x+l*y)/SUB] >> (x+l*y)%SUB & 1; }
    void one(int x, int y) { m[(x+l*y)/SUB] |= 1U << (x+l*y)%SUB; }
    void zero(int x, int y) { m[(x+l*y)/SUB] &= ~(1U << (x+l*y)%SUB); }
} g;

unt c(a*A, vec x, unt rlen, unt sn) {
    if((unt)x.y+abs(x.x) > rlen) return 0;
    if(!rlen) {
        vec *cl=X, *cr=X, *ct=X;
        for(unt i=1; i<sn; i++) {
            #define BLAH(Z,A,B,o,O) \
                if(X[i].A o Z->A || (X[i].A == Z->A && X[i].B O Z->B)) \
                   Z = X+i

            BLAH(cl,x,y,<,>);
            BLAH(cr,x,y,>,<);
            BLAH(ct,y,x,>,>);
        }
        unt syms = 1;
        #define BLA(H,Z) {bool sy=1;for(unt o=0; o<sn; o++) sy &= (int)(1|-(H))*sl[o] == sl[(Z-X+o)%sn]; syms += sy;}
        BLA(~o&1,cl)
        BLA(1,ct)
        BLA(o&1,cr)

        #ifdef D
            //printf("D");for(int i=0;i<sn;i++)printf(" %u",sl[i]);printf("\n");
            if(syms==3) fail("symm");
        #endif

        return syms;
    }
    if(!(x.x|x.y|!sn)) return 0;
    X[sn] = x;

    unt k = 0;
    for(auto it: A->v) {
        int len = it.first;
        bool ve = sn&1;
        int dx = ve?0:len, dy = ve?len:0;

        #define PPCG(O)(x.x O (ve?0:z), x.y O (ve?z:0))
        #define MACR(O) { \
            vec v2 = {x.x O dx, x.y O dy}; \
            if(v2.y<0||(!v2.y&&v2.x<0)||abs(v2.x)>xM||v2.y>xM) \
                goto LBL; \
            for(int z=1; z<=len; z++) \
                if(g PPCG(O)) \
                    goto LBL; \
            for(int z=1; z<=len; z++) \
                g.one PPCG(O); \
            sl[sn] = O len; \
            k += c(blob+it.second, v2, rlen - len, sn+1); \
            for(int z=1; z<=len; z++) \
                g.zero PPCG(O); \
            } LBL: \

    MACR(+);
    MACR(-);
    }

    return k;
}

void stuff(a *n, unt j, unt r, unt len1)
{
    unt t=0;
    for(unt i=j; i<j+r; i++) {
        t += s[i];
        if((int)t > xM || (len1 && t>len1)) break;
        if(len1 && t < len1) continue;
        int r2 = r-(i-j)-1;
        if(r2) {
            unt x;
            if(n->v.count(t))
                x = n->v[t];
            else
                n->v[t] = x = newa - blob;
            stuff(blob+x, i+1, r2, 0);
        } else n->v[t] = -1;
    }
}

int main()
{
    time_t tim = time(0);
    blob = new a[SZ];
    int n;
    scanf("%u",&n);
    while(n--) {
        nb = 0;
        unt ns=0, tl=0;
        while(scanf("%u",s+ns)) {
            tl += s[ns];
            if(++ns==MS) return 1;
            if(getchar() < 11) break;
        }
        xM = ~-tl/2;
        g.m = (unt*)calloc((xM+1)*l/SU + 1,4);

        memcpy(s+ns, s, ns*SU);

        unt ans = 0;
        for(unt len1 = 1; (int)len1 <= xM; len1++) {
            a* a0 = newa;
            for(unt i=0; i<ns; i++)
                stuff(a0, i, ns, len1);
            ans += c(a0, {}, tl, 0);
            for(unt i=0; i<nb; i++)
                blob[i].v.clear();
        }
        printf("%d\n", ans/4);
        free(g.m);
    }

    tim = time(0) - tim;
    printf("time:%d",(int)tim);
    return 0;
}

संकलन

g++ --std=c++11 -O3 feersum.cpp -o feersum.exe

डोज़ #defineएस थो
सोहम चौधरी

किसी भी अन्य उत्तर के अभाव में ... यहाँ, एक इनाम है!
Sp3000

3

पायथन 3 ( PyPy के साथ ) - N = 18

ANGLE_COMPLEMENTS = {"A": "C", "F": "F", "C": "A"}
MOVE_ENUMS = {"U": 0, "R": 1, "D": 2, "L": 3}
OPPOSITE_DIR = {"U": "D", "D": "U", "L": "R", "R": "L", "": ""}

def canonical(angle_str):
    return min(angle_str[i:] + angle_str[:i] for i in range(len(angle_str)))

def to_angles(moves):
    """
    Convert a string of UDLR to a string of angles where
      A -> anticlockwise turn
      C -> clockwise turn
      F -> forward
    """

    angles = []

    for i in range(1, len(moves)):
        if moves[i] == moves[i-1]:
            angles.append("F")
        elif (MOVE_ENUMS[moves[i]] - MOVE_ENUMS[moves[i-1]]) % 4 == 1:
            angles.append("C")
        else:
            angles.append("A")

    if moves[0] == moves[len(moves)-1]:
        angles.append("F")
    elif (MOVE_ENUMS[moves[0]] - MOVE_ENUMS[moves[len(moves)-1]]) % 4 == 1:
        angles.append("C")
    else:
        angles.append("A")

    return "".join(angles)

def solve(rods):
    FOUND_ANGLE_STRS = set()

    def _solve(rods, rod_sum, point=(0, 0), moves2=None, visited=None, last_dir=""):
        # Stop when point is too far from origin
        if abs(point[0]) + abs(point[1]) > rod_sum:
            return

        # No more rods, check if we have a valid solution
        if not rods:
            if point == (0, 0):
               angle_str = to_angles("".join(moves2))

               if angle_str.count("A") - angle_str.count("C") == 4:
                   FOUND_ANGLE_STRS.add(canonical(angle_str))

            return

        r = rods.pop(0)

        if not visited:
            visited = set()
            move_dirs = [((r, 0), "R")]
            moves2 = []

        else:
            move_dirs = [((r,0), "R"), ((0,r), "U"), ((-r,0), "L"), ((0,-r), "D")]

        opp_dir = OPPOSITE_DIR[last_dir]

        for move, direction in move_dirs:
            if direction == opp_dir: continue

            new_point = (move[0] + point[0], move[1] + point[1])
            added_visited = set()
            search = True

            for i in range(min(point[0],new_point[0]), max(point[0],new_point[0])+1):
                for j in range(min(point[1],new_point[1]), max(point[1],new_point[1])+1):
                    if (i, j) != point:
                        if (i, j) in visited:
                            search = False

                            for a in added_visited:
                                visited.remove(a)

                            added_visited = set()                            
                            break

                        else:
                            visited.add((i, j))
                            added_visited.add((i, j))

                if not search:
                    break

            if search:
                moves2.append(direction*r)
                _solve(rods, rod_sum-r, new_point, moves2, visited, direction)
                moves2.pop()

            for a in added_visited:
                visited.remove(a)

        rods.insert(0, r)
        return

    _solve(rods, sum(rods))
    return len(FOUND_ANGLE_STRS)

num_rods = int(input())

for i in range(num_rods):
    rods = [int(x) for x in input().split(" ")]
    print(solve(rods))

साथ चलाना ./pypy <filename>


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

N = 18 को मेरे मामूली लैपटॉप पर लगभग 2.5 मिनट लगते हैं।

कलन विधि

प्रत्येक आकृति को Fआगे की श्रृंखला के लिए, Aएंटीलॉकवाइज़ मोड़ के लिए और Cआकृति की सीमा पर प्रत्येक जाली बिंदु पर दक्षिणावर्त मोड़ के लिए घुमाव की जाँच की जाती है - मैं इसे कोण स्ट्रिंग कहता हूं । यदि उनके कोण तार चक्रीय क्रमपरिवर्तन हैं, तो दो आकार घूर्णी रूप से समान हैं। हमेशा दो कोणों के तारों की सीधे तुलना करके इसकी जांच करने के बजाय, जब हम एक नया आकार पाते हैं तो हम भंडारण से पहले एक विहित रूप में परिवर्तित हो जाते हैं। जब हमारे पास एक नया उम्मीदवार होता है, तो हम विहित रूप में परिवर्तित हो जाते हैं और जांचते हैं कि क्या हमारे पास पहले से ही (इस तरह से हैशिंग का शोषण करने के बजाय, पूरे सेट के माध्यम से पुनरावृत्ति करता है)।

कोण स्ट्रिंग का उपयोग यह जांचने के लिए भी किया जाता है कि आकृति एंटीक्लॉकवाइज बनाई गई है, यह सुनिश्चित करके कि Aएस की संख्या C4 से एस की संख्या से अधिक है ।

आत्म-चौराहे को आकार की सीमा पर प्रत्येक जाली बिंदु को संग्रहीत करके भोलेपन से जांचा जाता है, और यह देखने के लिए कि एक बिंदु पर दो बार जाया जाता है या नहीं।

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

अपडेट (पहले नवीनतम)

  • 6/12: पेश किया गया विहित रूप, कुछ सूक्ष्म-अनुकूलन जोड़े
  • 5/12: एल्गोरिथ्म स्पष्टीकरण में निश्चित त्रुटि। द्विघात, चक्रीय-क्रमचय-जाँच एल्गोरिथ्म को A, B चक्रीय क्रमपरिवर्तन का उपयोग करके रैखिक बना दिया, यदि B + B विधि का एक विकल्प (मुझे नहीं पता कि मैंने ऐसा पहले क्यों नहीं किया)।
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.