अंतरालों को पाटो


14

एक सफेद पृष्ठभूमि और काले डॉट्स के एक सेट के साथ एक काले और सफेद छवि को देखते हुए, सफेद पिक्सेल लाल रंग के एक सेट को पेंट करें, जैसे कि ब्लैक पिक्सल के प्रत्येक जोड़े के बीच एक रास्ता है।

विवरण

  • एक पथ कनेक्टेड पिक्सल (8-पड़ोस कनेक्टिविटी) का एक सेट है। ब्लैक पिक्सल्स को रास्तों के हिस्से के रूप में इस्तेमाल किया जा सकता है। लक्ष्य उपरोक्त शर्तों के तहत लाल पिक्सेल के सेट को कम करने की कोशिश कर रहा है, और इसी छवि को आउटपुट कर रहा है।

  • आपको इष्टतम समाधान खोजने की आवश्यकता नहीं है

  • एक तुच्छ और एक ही समय में सबसे खराब समाधान सिर्फ सभी सफेद पिक्सेल को लाल कर रहा है।

  • उदाहरण (पिक्सेल दृश्यता के लिए बढ़े हुए हैं):

विवरण

  • एक पिक्सेल छवि को देखते हुए (किसी भी उपयुक्त प्रारूप में) ऊपर निर्दिष्ट के रूप में जुड़े डॉट्स के साथ एक और छवि लौटाते हैं, साथ ही एक पूर्णांक दर्शाता है कि कितने लाल पिक्सेल का उपयोग किया गया था।
  • स्कोर 14 टेस्टकेस में से प्रत्येक के लिए (1 + लाल पिक्सेल की संख्या) का उत्पाद है।
  • लक्ष्य का स्कोर सबसे कम है।

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

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

मेटा

विभिन्न सुझावों के लिए @Veskah, @Fatalize, @ wizzwizz4 और @trichoplax का धन्यवाद।


1
अच्छी चुनौती; मुझे अलग और रचनात्मक स्कोरिंग योजनाएं पसंद हैं। मुझे लगता है कि कार्यक्रम को केवल 14 विशिष्ट उदाहरणों से नहीं, बल्कि एक मनमानी छवि पर काम करने की आवश्यकता है? यदि हां, तो हम मोना लिसा छवि प्रति 512x512, या 1024x1024 जैसे एक उचित अधिकतम आकार मान सकते हैं?
ब्रैडक

प्रतिक्रिया के लिए धन्यवाद! हाँ, आप अधिकतम आकार (यदि आवश्यक हो तो एक न्यूनतम आकार) मान सकते हैं, जब तक कि सभी 14 उदाहरण संसाधित किए जा सकते हैं।
दोष

कैसे मैं png को ascii या json या किसी अन्य चीज़ से पार्स में परिवर्तित कर सकता हूँ?
ngn

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

1
@ GIMP में खोलें, netpbm प्रारूप के रूप में सहेजें।
wizzwizz4 12

जवाबों:


7

सी, स्कोर 2.397x10 ^ 38

मैन यह करने के लिए बहुत लंबा रास्ता तय किया, सबसे अधिक संभावना भाषा की मेरी पसंद के कारण। मुझे एल्गोरिथ्म काफी पहले से काम कर रहा था, लेकिन मेमोरी आवंटन के साथ बहुत सारी समस्याओं में भाग गया (स्टैक ओवरफ्लो के कारण पुन: मुक्त सामान नहीं कर सका, रिसाव आकार बहुत बड़ा था)।

फिर भी! यह हर परीक्षण के मामले में अन्य प्रविष्टि को धड़कता है, और इष्टतम भी हो सकता है बहुत पास या बिल्कुल इष्टतम समाधान बहुत समय मिलता है।

वैसे भी, यहाँ कोड है:

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

#define WHITE 'W'
#define BLACK 'B'
#define RED   'R'


typedef struct image {
    int w, h;
    char* buf;
} image;

typedef struct point {
    int x, y;
    struct point *next;
    struct point *parent;
} point;

typedef struct shape {
    point* first_point;
    point* last_point;

    struct shape* next_shape;
} shape;


typedef struct storage {
    point* points;
    size_t points_size;
    size_t points_index;

    shape* shapes;
    size_t shapes_size;
    size_t shapes_index;
} storage;

char getpx(image* img, int x, int y) {
    if (0>x || x>=img->w || 0>y || y>=img->h) {
        return WHITE;
    } else {
        return img->buf[y*img->w+x];
    }
}

storage* create_storage(int w, int h) {
    storage* ps = (storage*)malloc(sizeof(storage));

    ps->points_size = 8*w*h;
    ps->points = (point*)calloc(ps->points_size, sizeof(point));
    ps->points_index = 0;

    ps->shapes_size = 2*w*h;
    ps->shapes = (shape*)calloc(ps->shapes_size, sizeof(shape));
    ps->shapes_index = 0;

    return ps;
}

void free_storage(storage* ps) {
    if (ps != NULL) {
        if (ps->points != NULL) {
            free(ps->points);
            ps->points = NULL;
        }
        if (ps->shapes != NULL) {
            free(ps->shapes);
            ps->shapes = NULL;
        }
        free(ps);
    }
}


point* alloc_point(storage* ps) {
    if (ps->points_index == ps->points_size) {
        printf("WHOAH THERE BUDDY SLOW DOWN\n");
        /*// double the size of the buffer
        point* new_buffer = (point*)malloc(ps->points_size*2*sizeof(point));
        // need to change all existing pointers to point to new buffer
        long long int pointer_offset = (long long int)new_buffer - (long long int)ps->points;
        for (size_t i=0; i<ps->points_index; i++) {
            new_buffer[i] = ps->points[i];
            if (new_buffer[i].next != NULL) {
                new_buffer[i].next += pointer_offset;
            }
            if (new_buffer[i].parent != NULL) {
                new_buffer[i].parent += pointer_offset;
            }
        }

        for(size_t i=0; i<ps->shapes_index; i++) {
            if (ps->shapes[i].first_point != NULL) {
                ps->shapes[i].first_point += pointer_offset;
            }
            if (ps->shapes[i].last_point != NULL) {
                ps->shapes[i].last_point += pointer_offset;
            }
        }

        free(ps->points);
        ps->points = new_buffer;
        ps->points_size = ps->points_size * 2;*/
    }
    point* out = &(ps->points[ps->points_index]);
    ps->points_index += 1;
    return out;
}

shape* alloc_shape(storage* ps) {
    /*if (ps->shapes_index == ps->shapes_size) {
        // double the size of the buffer
        shape* new_buffer = (shape*)malloc(ps->shapes_size*2*sizeof(shape));
        long long int pointer_offset = (long long int)new_buffer - (long long int)ps->shapes;
        for (size_t i=0; i<ps->shapes_index; i++) {
            new_buffer[i] = ps->shapes[i];
            if (new_buffer[i].next_shape != NULL) {
                new_buffer[i].next_shape += pointer_offset;
            }
        }
        free(ps->shapes);
        ps->shapes = new_buffer;
        ps->shapes_size = ps->shapes_size * 2;
    }*/
    shape* out = &(ps->shapes[ps->shapes_index]);
    ps->shapes_index += 1;
    return out;
}

shape floodfill_shape(image* img, storage* ps, int x, int y, char* buf) {
    // not using point allocator for exploration stack b/c that will overflow it

    point* stack = (point*)malloc(sizeof(point));
    stack->x = x;
    stack->y = y;
    stack->next = NULL;
    stack->parent = NULL;

    point* explored = NULL;
    point* first_explored;
    point* next_explored;

    while (stack != NULL) {
        int sx = stack->x;
        int sy = stack->y;
        point* prev_head = stack;
        stack = stack->next;
        free(prev_head);

        buf[sx+sy*img->w] = 1; // mark as explored

        // add point to shape
        next_explored = alloc_point(ps);
        next_explored->x = sx;
        next_explored->y = sy;
        next_explored->next = NULL;
        next_explored->parent = NULL;

        if (explored != NULL) {
            explored->next = next_explored;
        } else {
            first_explored = next_explored;
        }
        explored = next_explored;

        for (int dy=-1; dy<2; dy++) {
        for (int dx=-1; dx<2; dx++) {
            if (dy != 0 || dx != 0) {
                int nx = sx+dx;
                int ny = sy+dy;
                if (getpx(img, nx, ny) == WHITE || buf[nx+ny*img->w]) {
                    // skip adding point to fringe
                } else {
                    // push point to top of stack
                    point* new_point = (point*)malloc(sizeof(point));
                    new_point->x = nx;
                    new_point->y = ny;
                    new_point->next = stack;
                    new_point->parent = NULL;

                    stack = new_point;
                } 
            }
        }
        }
    }

    /*if (getpx(img, x, y) == WHITE || buf[x+y*img->w]) {
        return (shape){NULL, NULL, NULL};
    } else {
        buf[x+y*img->w] = 1;

        shape e  = floodfill_shape(img, ps, x+1, y,   buf);
        shape ne = floodfill_shape(img, ps, x+1, y+1, buf);
        shape n  = floodfill_shape(img, ps, x,   y+1, buf);
        shape nw = floodfill_shape(img, ps, x-1, y+1, buf);
        shape w  = floodfill_shape(img, ps, x-1, y,   buf);
        shape sw = floodfill_shape(img, ps, x-1, y-1, buf);
        shape s  = floodfill_shape(img, ps, x,   y-1, buf);
        shape se = floodfill_shape(img, ps, x+1, y-1, buf);

        point *p = alloc_point(ps);
        p->x = x;
        p->y = y;
        p->next = NULL;
        p->parent = NULL;

        shape o = (shape){p, p, NULL};
        if (e.first_point != NULL) {
            o.last_point->next = e.first_point;
            o.last_point = e.last_point;
        }
        if (ne.first_point != NULL) {
            o.last_point->next = ne.first_point;
            o.last_point = ne.last_point;
        }
        if (n.first_point != NULL) {
            o.last_point->next = n.first_point;
            o.last_point = n.last_point;
        }
        if (nw.first_point != NULL) {
            o.last_point->next = nw.first_point;
            o.last_point = nw.last_point;
        }
        if (w.first_point != NULL) {
            o.last_point->next = w.first_point;
            o.last_point = w.last_point;
        }
        if (sw.first_point != NULL) {
            o.last_point->next = sw.first_point;
            o.last_point = sw.last_point;
        }
        if (s.first_point != NULL) {
            o.last_point->next = s.first_point;
            o.last_point = s.last_point;
        }
        if (se.first_point != NULL) {
            o.last_point->next = se.first_point;
            o.last_point = se.last_point;
        }

        return o;
    }*/

    shape out = {first_explored, explored, NULL};

    return out;
}

shape* create_shapes(image* img, storage* ps) {
    char* added_buffer = (char*)calloc(img->w*img->h, sizeof(char));
    shape* first_shape = NULL;
    shape* last_shape = NULL;
    int num_shapes = 0;
    for (int y=0; y<img->h; y++) {
        for (int x=0; x<img->w; x++) {
            if (getpx(img, x, y) != WHITE && !(added_buffer[x+y*img->w])) {
                shape* alloced_shape = alloc_shape(ps);
                *alloced_shape = floodfill_shape(img, ps, x, y, added_buffer);

                if (first_shape == NULL) {
                    first_shape = alloced_shape;
                    last_shape = alloced_shape;
                } else if (last_shape != NULL) {
                    last_shape->next_shape = alloced_shape;
                    last_shape = alloced_shape;
                }

                num_shapes++;
            }
        }
    }

    free(added_buffer);

    return first_shape;
}

void populate_buf(image* img, shape* s, char* buf) {
    point* p = s->first_point;

    while (p != NULL) {
        buf[p->x+p->y*img->w] = 1;
        p = p->next;
    }
}

bool expand_frontier(image* img, storage* ps, shape* prev_frontier, shape* next_frontier, char* buf) {
    point* p = prev_frontier->first_point;
    point* n = NULL;

    bool found = false;

    size_t starting_points_index = ps->points_index;

    while (p != NULL) {
        for (int dy=-1; dy<2; dy++) {
        for (int dx=-1; dx<2; dx++) {
            if (dy != 0 || dx != 0) {
                int nx = p->x+dx;
                int ny = p->y+dy;
                if ((0<=nx && nx<img->w && 0<=ny && ny<img->h) // in bounds
                        && !buf[nx+ny*img->w]) {               // not searched yet
                    buf[nx+ny*img->w] = 1;
                    if (getpx(img, nx, ny) != WHITE) {
                        // found a new shape!
                        ps->points_index = starting_points_index;
                        n = alloc_point(ps);
                        n->x = nx;
                        n->y = ny;
                        n->next = NULL;
                        n->parent = p;
                        found = true;
                        goto __expand_frontier_fullbreak;
                    } else {
                        // need to search more
                        point* f = alloc_point(ps);
                        f->x = nx;
                        f->y = ny;
                        f->next = n;
                        f->parent = p;
                        n = f;
                    }
                }
            }
        }}

        p = p->next;
    }
__expand_frontier_fullbreak:
    p = NULL;
    point* last_n = n;
    while (last_n->next != NULL) {
        last_n = last_n->next;
    }

    next_frontier->first_point = n;
    next_frontier->last_point = last_n;

    return found;
}

void color_from_frontier(image* img, point* frontier_point) {
    point* p = frontier_point->parent;

    while (p->parent != NULL) { // if everything else is right,
                                // a frontier point should come in a chain of at least 3
                                // (f point (B) -> point to color (W) -> point in shape (B) -> NULL)
        img->buf[p->x+p->y*img->w] = RED;
        p = p->parent;
    }
}

int main(int argc, char** argv) {
    if (argc < 3) {
        printf("Error: first argument must be filename to load, second argument filename to save to.\n");
        return 1;
    }

    char* fname = argv[1];
    FILE* fp = fopen(fname, "r");

    if (fp == NULL) {
        printf("Error opening file \"%s\"\n", fname);
        return 1;
    }

    int w, h;
    w = 0;
    h = 0;
    fscanf(fp, "%d %d\n", &w, &h);

    if (w==0 || h==0) {
        printf("Error: invalid width/height specified\n");
        return 1;
    }

    char* buf = (char*)malloc(sizeof(char)*w*h+1);
    fgets(buf, w*h+1, fp);
    fclose(fp);

    image img = (image){w, h, buf};

    int nshapes = 0;
    storage* ps = create_storage(w, h);

    while (nshapes != 1) {
        // main loop, do processing step until one shape left
        ps->points_index = 0;
        ps->shapes_index = 0;

        shape* head = create_shapes(&img, ps);
        nshapes = 0;
        shape* pt = head;
        while (pt != NULL) {
            pt = pt->next_shape;
            nshapes++;
        }
        if (nshapes % 1024 == 0) {
            printf("shapes left: %d\n", nshapes);
        }
        if (nshapes == 1) {
            goto __main_task_complete;
        }


        shape* frontier = alloc_shape(ps);
        // making a copy so we can safely free later
        point* p = head->first_point;
        point* ffp = NULL;
        point* flp = NULL;
        while (p != NULL) {
            if (ffp == NULL) {
                ffp = alloc_point(ps);
                ffp->x = p->x;
                ffp->y = p->y;
                ffp->next = NULL;
                ffp->parent = NULL;
                flp = ffp;
            } else {
                point* fnp = alloc_point(ps);
                fnp->x = p->x;
                fnp->y = p->y;
                fnp->next = NULL;
                fnp->parent = NULL;

                flp->next = fnp;
                flp = fnp;
            }

            p = p->next;
        }
        frontier->first_point = ffp;
        frontier->last_point = flp;
        frontier->next_shape = NULL;

        char* visited_buf = (char*)calloc(img.w*img.h+1, sizeof(char));
        populate_buf(&img, frontier, visited_buf);

        shape* new_frontier = alloc_shape(ps);
        new_frontier->first_point = NULL;
        new_frontier->last_point = NULL;
        new_frontier->next_shape = NULL;

        while (!expand_frontier(&img, ps, frontier, new_frontier, visited_buf)) {
            frontier->first_point = new_frontier->first_point;
            frontier->last_point = new_frontier->last_point;
            new_frontier->next_shape = frontier;
        }

        free(visited_buf);
        color_from_frontier(&img, new_frontier->first_point);
__main_task_complete:
        img = img;
    }

    free_storage(ps);

    char* outfname = argv[2];
    fp = fopen(outfname, "w");

    if (fp == NULL) {
        printf("Error opening file \"%s\"\n", outfname);
        return 1;
    }

    fprintf(fp, "%d %d\n", img.w, img.h);
    fprintf(fp, "%s", img.buf);

    free(img.buf);

    fclose(fp);

    return 0;
}

पर परीक्षण किया गया: आर्क लिनक्स, जीसीसी 9.1.0, -O3

यह कोड एक कस्टम फ़ाइल में इनपुट / आउटपुट लेता है जिसे मैं "सीपीएम" कहता हूं (क्योंकि यह क्लासिक पीपीएम प्रारूप का एक संघनित संस्करण जैसा है)। एक पायथन लिपि को इससे / से परिवर्तित करने के लिए नीचे है:

from PIL import Image

BLACK='B'
WHITE='W'
RED  ='R'


def image_to_cppm(infname, outfname):
    outfile = open(outfname, 'w')
    im = Image.open(infname)

    w, h = im.width, im.height
    outfile.write(f"{w} {h}\n")
    for y in range(h):
        for x in range(w):
            r, g, b, *_ = im.getpixel((x, y))
            if r==0 and g==0 and b==0:
                outfile.write(BLACK)
            elif g==0 and b==0:
                outfile.write(RED)
            else:
                outfile.write(WHITE)
    outfile.write("\n")
    outfile.close()
    im.close()

def cppm_to_image(infname, outfname):
    infile = open(infname, 'r')

    w, h = infile.readline().split(" ")
    w, h = int(w), int(h)

    im = Image.new('RGB', (w, h), color=(255, 255, 255))

    for y in range(h):
        for x in range(w):
            c = infile.read(1)
            if c==BLACK:
                im.putpixel((x,y), (0, 0, 0))
            elif c==RED:
                im.putpixel((x,y), (255, 0, 0))

    infile.close()
    im.save(outfname)
    im.close()


if __name__ == "__main__":
    import sys
    if len(sys.argv) < 3:
        print("Error: must provide 2 files to convert, first is from, second is to")

    infname = sys.argv[1]
    outfname = sys.argv[2]

    if not infname.endswith("cppm") and outfname.endswith("cppm"):
        image_to_cppm(infname, outfname)
    elif infname.endswith("cppm") and not outfname.endswith("cppm"):
        cppm_to_image(infname, outfname)
    else:
        print("didn't do anything, exactly one file must end with .cppm")

एल्गोरिथम स्पष्टीकरण

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

छवि गैलरी

टेस्टकेस 1, 183 पिक्सेल

टेस्टकेस 1

टेस्टकेस 2, 140 पिक्सेल

अंडकोष 2

टेस्टकेस 3, 244 पिक्सेल

टेस्टकेस 3

टेस्टकेस 4, 42 पिक्सल

टेस्टकेस ४

टेस्टकेस 5, 622 पिक्सेल

टेस्टकेस ५

टेस्टकेस 6, 1 पिक्सेल

टेस्टकेस 6

टेस्टकेस 7, 104 पिक्सेल

टेस्टकेस 7

टेस्टकेस 8, 2286 पिक्सेल

अंडकोष 8

टेस्टकेस 9, 22 पिक्सेल

टेस्टकेस 9

टेस्टकेस 10, 31581 पिक्सल

टेस्टकेस १०

टेस्टकेस 11, 21421 पिक्सल

टेस्टकेस ११

टेस्टकेस 12, 5465 पिक्सल

टेस्टकेस १२

टेस्टकेस 13, 4679 पिक्सेल

टेस्टकेस १३

टेस्टकेस 14, 7362 पिक्सेल

अंडकोष १४


2
अच्छा काम! बहुत कुशल लगता है, हालांकि मैं थोड़ा और अधिक इष्टतम समाधानों के साथ कुछ आकृतियों की कल्पना कर सकता हूं: टेस्टकेस 3 (एक वर्ग में 4 डॉट्स), उदाहरण के लिए, मैंने (मैन्युअल रूप से) 175 (एक लाल एक्स) के रूप में कम पाया, निश्चित नहीं कि कैसे मुझे लगता है कि एल्गोरिथ्म के माध्यम से मजबूर करता हूँ।
ब्रैड

6

पायथन, 2.62 * 10 ^ 40

यह एल्गोरिदम सिर्फ बाढ़ (बीएफएस) छवि के काले हिस्सों से शुरू होने वाला विमान है, जहां प्रत्येक नए पिक्सेल के लिए हम रिकॉर्ड करते हैं कि यह किस काले हिस्से से भरा गया था। जैसे ही हमारे पास पूर्वजों के रूप में अलग-अलग काले हिस्सों के साथ दो पड़ोसी पिक्सेल होते हैं, हम मूल रूप से इन दो काले भागों को मर्ज करते हैं, जो हमने अभी-अभी मिले दो पड़ोसियों के पूर्वजों के माध्यम से जोड़ दिए हैं। सिद्धांत रूप में इसे लागू किया जा सकता है O(#pixels), लेकिन स्वीकार्य स्तर पर कोड की मात्रा को बनाए रखने के लिए यह कार्यान्वयन थोड़ा खराब है।

उत्पादन

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

import numpy as np
from scipy import ndimage
import imageio
from collections import deque

# path to your image
for k in range(1, 15):
    fname=str(k).zfill(2) +'.png'
    print("processing ", fname)

    # load image
    img = imageio.imread("./images/"+fname, pilmode="RGB")
    print(img.shape)

    # determine non_white part
    white = np.logical_and(np.logical_and(img[:,:,0] == 255, img[:,:,1] == 255), img[:,:,2] == 255)
    non_white = np.logical_not(white)

    # find connected components of non-white part
    neighbourhood = np.ones((3,3))
    labeled, nr_objects = ndimage.label(non_white, neighbourhood)

    # print result
    print("number of separate objects is {}".format(nr_objects))

    # start flood filling algorithm
    ind = np.nonzero(labeled)
    front = deque(zip(ind[0],ind[1]))

    membership = np.copy(labeled)
    is_merge_point = np.zeros_like(labeled) > 0
    parent = np.zeros((2,) + labeled.shape) #find ancestor of each pixel
    is_seed = labeled > 0
    size_i, size_j = labeled.shape
    # flood from every seed
    while front: #while we have unexplored pixels
        point = front.popleft()
        # check neighbours:
        for (di,dj) in [(-1,-1),(-1,0),(-1,1),(0,-1),(0,1),(1,-1),(1,0),(1,1)]:
            current = membership[point[0], point[1]]
            new_i, new_j = point[0]+di, point[1]+dj
            if 0 <= new_i < size_i and 0 <= new_j < size_j:
                value = membership[new_i, new_j]
                if value == 0:
                    membership[new_i, new_j] = current
                    front.append((new_i, new_j))
                    parent[:, new_i, new_j] = point
                elif value != current: #MERGE!
                    is_merge_point[point[0], point[1]] = True
                    is_merge_point[new_i, new_j] = True
                    membership[np.logical_or(membership == value, membership == current)] = min(value, current)

    # trace back from every merger
    ind = np.nonzero(is_merge_point)
    merge_points = deque(zip(ind[0].astype(np.int),ind[1].astype(np.int)))
    for point in merge_points:
        next_p = point
        while not is_seed[next_p[0], next_p[1]]:
            is_merge_point[next_p[0], next_p[1]] = True
            next_p = parent[:, next_p[0], next_p[1]].astype(np.int)

    # add red points:
    img_backup = np.copy(img)
    img[:,:,0][is_merge_point] = 255 * img_backup[:,:,0]
    img[:,:,1][is_merge_point] = 0   * img_backup[:,:,1]
    img[:,:,2][is_merge_point] = 0   * img_backup[:,:,2]

    #compute number of new points
    n_red_points = (img[:,:,0] != img[:,:,1]).sum()
    print("#red points:", n_red_points)

    # plot: each component should have separate color
    imageio.imwrite("./out_images/"+fname, np.array(img))

स्कोर

(1+183)*(1+142)*(1+244)*(1+42)*(1+1382)*(1+2)*(1+104)*(1+7936)*(1+26)*(1+38562)*(1+42956)*(1+6939)*(1+8882)*(1+9916)
= 26208700066468930789809050445560539404000
= 2.62 * 10^40

- यह, मेरा मानना ​​है, इष्टतम है। शाबाश ।-- ठीक है, यह इष्टतम नहीं है। मुझे समझ में नहीं आता क्यों नहीं।
wizzwizz4

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

@ wizzwizz4 हां, विकिपीडिया पाठ उदाहरण पर ज़ूम इन करें, और आप कई छोटे स्थानों को देखेंगे जहां एक अलग कनेक्टिंग पथ ने एक लाल पिक्सेल या दो को बचाया होगा; वे जोड़ देंगे।
ब्रैडेक

लेकिन यह खूंटे पर साबुन-बुलबुले की तरह लगता है, जो कि स्टीनर ट्री समस्या का एक वैध समाधान है
wizzwizz4

1
@ wizzwizz4, अंतर यह होना चाहिए कि हम पॉइंट्स कनेक्ट नहीं कर रहे हैं , हम पॉइंट्स के सेट कनेक्ट कर रहे हैं , इसलिए हमें यह तय नहीं करना चाहिए कि प्रत्येक सेट में कौन से पॉइंट्स को एक इष्टतम तरीके से कनेक्ट करना है। पाठ के उदाहरण में फिर से ज़ूम करें, जो सुधार आप देख सकते हैं वह अधिकतर प्रत्येक आकृति के किन हिस्सों से जुड़े हैं।
बजे ब्रैडक

5

अजगर 3: 1.7x10 ^ 42 1.5x10 ^ 41

का उपयोग कर Pillow, numpyऔर scipy

छवियों को imagesस्क्रिप्ट के समान निर्देशिका में स्थित फ़ोल्डर में माना जाता है ।

अस्वीकरण : सभी छवियों को संसाधित करने में लंबा समय लगता है।

कोड

import sys
import os

from PIL import Image
import numpy as np
import scipy.ndimage


def obtain_groups(image, threshold, structuring_el):
    """
    Obtain isles of unconnected pixels via a threshold on the R channel
    """
    image_logical = (image[:, :, 1] < threshold).astype(np.int)
    return scipy.ndimage.measurements.label(image_logical, structure=structuring_el)


def swap_colors(image, original_color, new_color):
    """
    Swap all the pixels of a specific color by another color 
    """
    r1, g1, b1 = original_color  # RGB value to be replaced
    r2, g2, b2 = new_color  # New RGB value
    red, green, blue = image[:, :, 0], image[:, :, 1], image[:, :, 2]
    mask = (red == r1) & (green == g1) & (blue == b1)
    image[:, :, :3][mask] = [r2, g2, b2]
    return image


def main(image_path=None):
    images = os.listdir("images")
    f = open("results.txt", "w")

    if image_path is not None:
        images = [image_path]

    for image_name in images:
        im = Image.open("images/"+image_name).convert("RGBA")
        image = np.array(im)

        image = swap_colors(image, (255, 255, 255), (255, 0, 0))

        # create structuring element to determine unconnected groups of pixels in image
        s = scipy.ndimage.morphology.generate_binary_structure(2, 2)

        for i in np.ndindex(image.shape[:2]):
            # skip black pixels
            if sum(image[i[0], i[1]]) == 255:
                continue
            image[i[0], i[1]] = [255, 255, 255, 255]
            # label the different groups, considering diagonal connections as valid
            groups, num_groups = obtain_groups(image, 255, s)
            if num_groups != 1:
                image[i[0], i[1]] = [255, 0, 0, 255]
            # Show percentage
            print((i[1] + i[0]*im.size[0])/(im.size[0]*im.size[1]))

        # Number of red pixels
        red_p = 0
        for i in np.ndindex(image.shape[:2]):
            j = (im.size[1] - i[0] - 1, im.size[0] - i[1] - 1)
            # skip black and white pixels
            if sum(image[j[0], j[1]]) == 255 or sum(image[j[0], j[1]]) == 255*4:
                continue
            image[j[0], j[1]] = [255, 255, 255, 255]
            # label the different groups, considering diagonal connections as valid
            groups, num_groups = obtain_groups(image, 255, s)
            if num_groups != 1:
                image[j[0], j[1]] = [255, 0, 0, 255]
            # Show percentage
            print((j[1] + j[0]*im.size[0])/(im.size[0]*im.size[1]))
            red_p += (sum(image[j[0], j[1]]) == 255*2)

        print(red_p)
        f.write("r_"+image_name+": "+str(red_p)+"\n")

        im = Image.fromarray(image)
        im.show()
        im.save("r_"+image_name)
    f.close()


if __name__ == "__main__":
    if len(sys.argv) == 2:
        main(sys.argv[1])
    else:
        main()

व्याख्या

साधारण समाधान। हम एक छवि में सभी सफेद पिक्सेल के रंग को लाल रंग में बदलकर शुरू करते हैं। ऐसा करने से, यह गारंटी दी जाती है कि सभी तत्व (काले पिक्सेल का कोई भी आइल) जुड़ा हुआ है।

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

अपडेट करें

जैसा कि यह देखा जा सकता है (और अपेक्षित) केवल इस पद्धति का उपयोग करके प्राप्त कनेक्शन एक नियमित पैटर्न दिखाते हैं और कुछ मामलों में, जैसे कि 6 और 11 वीं छवियों में, अनावश्यक लाल पिक्सेल हैं।

यह अतिरिक्त लाल पिक्सेल आसानी से छवि पर फिर से पुनरावृत्ति करके और ऊपर बताए गए समान कार्यों को निष्पादित करके हटाया जा सकता है लेकिन नीचे दाएं कोने से ऊपर बाएं कोने तक। यह दूसरा पास बहुत तेज़ है क्योंकि लाल पिक्सेल की मात्रा की जाँच की जानी है।

परिणाम

दूसरे पास के बाद संशोधित की गई छवियों को अंतर दिखाने के लिए दो बार सूचीबद्ध किया गया है।

18,825

लाल पिक्सेल की संख्या: 18825

334

लाल पिक्सेल की संख्या: 334

1352

लाल पिक्सेल की संख्या: 1352

20214

लाल पिक्सेल की संख्या: 20214

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

लाल पिक्सेल की संख्या: 47268

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

लाल पिक्सेल की संख्या: 63 27

17889

लाल पिक्सेल की संख्या: 17889

259

लाल पिक्सेल की संख्या: 259

6746

लाल पिक्सेल की संख्या: 6746

586

लाल पिक्सेल की संख्या: 586

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

लाल पिक्सेल की संख्या: 9 1

126

लाल पिक्सेल की संख्या: 126

212

लाल पिक्सेल की संख्या: 212

683

लाल पिक्सेल की संख्या: 683

स्कोर अभिकलन:

(1 + 6746) * (1 + 126) * (1 + 259) * (1 + 17889) * (1 + 334) * (1 + 586) * (1 + 18825) * (1 + 9 9 5) * (1 + 9 9) * (1) +683) * (1 + 1352) * (1 + 20214) * (1 + 212) * (1 + 63) * (1 + 47268) = 17787000545058587209988713763645500800000 ~ 1.7x10 ^ 42

दूसरा पास जोड़ने के बाद अपडेट किया गया गणना स्कोर:

(1+ 18825) * (1+ 1352) * (1+ 20214) * (1+ 47268) * (1+ 27) * (1+ 17889) * (1+ 6746) * (1+ 586) * (1) + 1) * (1+ 126) * (1+ 212) * (1+ 334) * (1 + 259) * (1 + 683) = 1556362547692626380868077624543198532320000 ~ 1.5x10 ^ 41


अच्छा काम। ऐसा लगता है कि हमें वैज्ञानिक अंकन में इसे स्कोर करने की आवश्यकता हो सकती है: 1.7x10 ^ 42
ब्रैडेक
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.