রডস চেইন দিয়ে পলিওমিনোস গঠন করা


20

পটভূমি

রডগুলির একটি (বদ্ধ) শৃঙ্খলা বিবেচনা করুন, যার প্রত্যেকটির পূর্ণসংখ্যার দৈর্ঘ্য রয়েছে। প্রদত্ত শৃঙ্খলে আপনি কতগুলি স্বতন্ত্র গর্ত-মুক্ত পলিওমিনোস গঠন করতে পারেন? বা অন্য কথায়, অক্ষ-সারিবদ্ধ পক্ষের সাথে কতগুলি ভিন্ন স্ব-স্ব-ছেদ করা বহুভুজ আপনি প্রদত্ত শৃঙ্খল দিয়ে গঠন করতে পারেন?

আসুন একটি উদাহরণ তাকান। 1 এবং 2 দৈর্ঘ্যের 8 রড সমন্বিত একটি নির্দিষ্ট চেইন বিবেচনা করুন, যা আমরা হিসাবে প্রতিনিধিত্ব করতে পারি [1, 1, 2, 2, 1, 1, 2, 2]। আবর্তন এবং অনুবাদগুলি পর্যন্ত, কেবলমাত্র 8 টি সম্ভাব্য পলিমিনয়েস রয়েছে (আমরা বিভিন্ন প্রতিচ্ছবি গণনা করি):

এখানে চিত্র বর্ণনা লিখুন

এই প্রথম রডটি গা dark় নীল এবং তারপরে আমরা বহুভুজকে পাল্টা-ঘড়ির কাঁটা দিক থেকে অনুভূত করি।

ঘূর্ণন বোধ উপরোক্ত উদাহরণে ফলাফলকে প্রভাবিত করে না। তবে আসুন আরেকটি শৃঙ্খলা বিবেচনা করা যাক [3, 1, 1, 1, 2, 1, 1], যা নিম্নলিখিত 3 টি পলিওমিনোস দেয়:

এখানে চিত্র বর্ণনা লিখুন

লক্ষ্য করুন যে আমরা সর্বশেষ পলিওমিনোর প্রতিচ্ছবি অন্তর্ভুক্ত করি না , কারণ এটির জন্য ঘড়ির কাঁটার দিকের পথচলা দরকার require

যদি আমাদের একই দৈর্ঘ্যের আরও নমনীয় চেইন থাকে তবে [1, 1, 1, 1, 1, 1, 1, 1, 1, 1]আমরা 9 ​​টি মোট কয়েকটি পলিওনিনয়েসের মধ্যে উভয় প্রতিচ্ছবি তৈরি করতে সক্ষম হব:

এখানে চিত্র বর্ণনা লিখুন

চ্যালেঞ্জ

একটি চেইন একটি বিবরণ, একটি বিন্যাস বা অনুরূপ যেমন দেওয়া, রড ব্যবহার করে (ঘুর্ণন এবং অনুবাদ পর্যন্ত) স্বতন্ত্র polyominoes সংখ্যা আপনি গঠন করতে পারেন তা নির্ধারণ অনুক্রমে সময় ঘড়ির কাঁটার বিপরীতে অর্থে ঘের কাছাকাছি যাচ্ছে।

দয়া করে একটি পূর্ণাঙ্গ প্রোগ্রাম লিখুন এবং কমান্ড লাইন থেকে আপনার কোডটি সংকলন করতে (প্রযোজ্য ক্ষেত্রে) অন্তর্ভুক্ত করুন এবং আপনার কোডটি চালান। আপনার ভাষার জন্য দয়া করে একটি নিখরচায় সংকলক / দোভাষীর একটি লিঙ্ক অন্তর্ভুক্ত করুন।

আপনার প্রোগ্রামটি STDIN থেকে ইনপুটটি পড়া উচিত। প্রথম লাইনে একটি পূর্ণসংখ্যা এম থাকবে । পরবর্তী এম লাইনগুলি পরীক্ষার কেস হবে, যার প্রত্যেকটিই রড দৈর্ঘ্যের একটি স্থান-বিভাজিত তালিকা হবে। তোমার প্রোগ্রাম প্রিন্ট উচিত এম স্বতন্ত্র polyominoes সংখ্যা গঠিত যাবে না - প্রতিটি যা একটি একক পূর্ণসংখ্যা নিয়ে গঠিত stdout- এ, এর লাইন।

আপনার অবশ্যই একটি একক থ্রেড ব্যবহার করা উচিত।

আপনার প্রোগ্রামটি কোনও সময়ে 1 গিগাবাইটের বেশি মেমরি ব্যবহার করা উচিত নয়। (এটি সম্পূর্ণ কঠোর সীমা নয়, তবে আমি আপনার এক্সিকিউটেবলের মেমরির ব্যবহার নিরীক্ষণ করব এবং ধারাবাহিকভাবে 1 জিবি-র বেশি ব্যবহার করে এমন কোনও প্রক্রিয়া বা এর উপরে উল্লেখযোগ্যভাবে স্পাইকগুলি নষ্ট করব will)

অতিরিক্ত পরিমাণে প্রাক-গণনা রোধ করতে আপনার কোডটি 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 জিবি ব্যবহার করতে পারে? : পি
শুক্রবার

@ স্পার এটি ঘের যখন একটি কোণে নিজেকে স্পর্শ করতে পারে। উদাহরণস্বরূপ, এখানে 81 নং দেখুন। যে এক গণনা করা উচিত নয়।
মার্টিন এেন্ডার

@ ফেয়ারসাম সরলতার জন্য, আমি মাল্টি-থ্রেডিংয়ে না বলতে চাই (এবং চ্যালেঞ্জটি সম্পাদনা করব)।
মার্টিন এন্ডার

1
@ পিটারকাগি আপনি কি এই মন্তব্যটি ভুল চ্যালেঞ্জের বিষয়ে পোস্ট করেছেন? এটা দেখে মনে হচ্ছে উপর চলে গেছে উচিত এই এক
মার্টিন ইন্ডার

উত্তর:


5

সি ++ 11

আপডেটস: cদূরত্বটি উত্স থেকে খুব বেশি দূরে থাকলে এর প্রথম লাইনটি খুব দ্রুত ভেঙে যায় (যা ভেরিয়েবলটির পুরো উদ্দেশ্য ছিল rlen, তবে আমি এটি প্রথম সংস্করণে লিখতে ভুলে গেছি)। আমি এটিকে পরিবর্তন করে অনেক কম স্মৃতি ব্যবহার করেছি, তবে সময় সাপেক্ষে। এটি এখন আমার জন্য 5 মিনিটের নিচে N = 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 ( পাইপাই সহ ) - এন = 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জন্য এবং ঘড়ির কাঁটার দিকে আকৃতির সীমানায় প্রতিটি জাল পয়েন্টে ঘুরিয়ে দেওয়ার জন্য আবর্তনগুলি পরীক্ষা করা হয় - আমি এটিকে একটি কোণ স্ট্রিং বলি । দুটি আকৃতির ঘোরানুগতভাবে অভিন্ন হয় যদি তাদের কোণগুলির স্ট্রিং চক্রীয় ক্রম হয়। সরাসরি দুটি কোণের স্ট্রিং সরাসরি তুলনা করে এটি যাচাই করার পরিবর্তে, যখন আমরা একটি নতুন আকার পাই আমরা সংরক্ষণের আগে একটি ক্যানোনিকাল আকারে রূপান্তর করি। যখন আমাদের কাছে নতুন প্রার্থী রয়েছে, আমরা ক্যানোনিকাল ফর্মে রূপান্তর করি এবং আমাদের কাছে ইতিমধ্যে এটি রয়েছে কিনা তা পরীক্ষা করে দেখি (এভাবে পুরো সেটটি ঘুরিয়ে দেওয়ার পরিবর্তে হ্যাশিং শোষণ করে)।

কোণগুলির স্ট্রিংটিও পরীক্ষা করে ব্যবহার করে যে আকারটি অ্যান্টিલોকওয়াইজ তৈরি হয়েছে, এটি নিশ্চিত করে যে As এর সংখ্যা C4 দ্বারা s এর চেয়ে বেশি হয়ে গেছে ।

স্ব-ছেদটি আকৃতির সীমানায় প্রতিটি জাল পয়েন্ট সংরক্ষণ করে এবং বিন্দুটি দু'বার দেখা হয়েছে কিনা তা দেখে নির্লজ্জভাবে পরীক্ষা করা হয়।

মূল অ্যালগরিদমটি সহজ, প্রথম রডটি ডানদিকে রেখে, তারপর বাকী রডগুলির জন্য সমস্ত সম্ভাবনার চেষ্টা করে। যদি কাঠিগুলি এমন এক জায়গায় পৌঁছে যায় যা উত্স থেকে খুব বেশি দূরে থাকে (অর্থাত্ অবশিষ্ট রডের দৈর্ঘ্যের যোগফল মূল থেকে পয়েন্টের ম্যানহাটনের দূরত্বের চেয়ে কম), তবে আমরা অকালে সেই সাবট্রিটি অনুসন্ধান করা বন্ধ করি।

আপডেটস (সর্বশেষ প্রথম)

  • 6/12: প্রবর্তিত ক্যানোনিকাল ফর্ম, কয়েকটি মাইক্রো-অপটিমাইজেশন যুক্ত করেছে
  • 5/12: অ্যালগরিদমের ব্যাখ্যায় স্থির ত্রুটি। চৌম্বকীয় চক্রীয়-ক্রমাগতকরণ-পরীক্ষা-করা অ্যালগরিদম লিনিয়ারটি A, B ব্যবহার করে চক্রীয় ক্রান্তিকরণ iff B + B পদ্ধতির একটি স্ট্রিং থাকে (কেন আগে আমি এটি করিনি তা আমার কোনও ধারণা নেই)।
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.