ค้นหาชุดอิสระที่ใหญ่ที่สุดในกราฟที่มีลักษณะเป็นโครงตาข่ายขนาดสูง


16

สำหรับจำนวนเต็มบวกให้พิจารณาสตริงไบนารีทั้งหมดของความยาวn 2n-1สำหรับสตริงที่กำหนดSให้Lเป็นอาร์เรย์ของความยาวnซึ่งมีการนับจำนวนของ1ในย่อยของระยะเวลาในแต่ละของn Sตัวอย่างเช่นถ้าn=3และแล้วS = 01010 L=[1,2,1]เราเรียกอาร์เรย์นับLS

เราบอกว่าสองสายS1และS2ความยาวเดียวกันการแข่งขันถ้าอาร์เรย์นับของตนL1และL2มีคุณสมบัติที่L1[i] <= 2*L2[i]และสำหรับทุกL2[i] <= 2*L1[i]i

งาน

สำหรับการnเริ่มต้นที่เพิ่มขึ้นn=1ภารกิจคือการหาขนาดของชุดสตริงที่ใหญ่ที่สุดแต่ละความยาว2n-1เพื่อไม่ให้มีสองสตริงตรงกัน

nรหัสของคุณควรส่งออกจำนวนหนึ่งต่อมูลค่าของ

คะแนน

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

ตัวอย่างคำตอบ

สำหรับฉันได้รับn=1,2,3,42,4,10,16

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

คุณสามารถใช้ภาษาและไลบรารีใด ๆ ที่คุณต้องการ หากเป็นไปได้จะเป็นการดีที่จะสามารถเรียกใช้รหัสของคุณได้ดังนั้นโปรดระบุคำอธิบายโดยละเอียดเกี่ยวกับวิธีเรียกใช้ / รวบรวมรหัสของคุณใน linux หากเป็นไปได้

รายการชั้นนำ

  • 5โดย Martin BüttnerในMathematica
  • 6โดย Reto Koradi ในc ++ 2, 4, 10, 16, 31, 47, 75, 111, 164, 232, 328, 445, 606, 814, 1086ค่า 5 อันดับแรกเป็นที่รู้จักกันดีที่สุด
  • 7โดยปีเตอร์เทย์เลอร์ในJava 2, 4, 10, 16, 31, 47, 76, 111, 166, 235ค่า
  • 9โดย joriki ในJava 2, 4, 10, 16, 31, 47, 76, 112, 168ค่า

3
ฉันคิดว่ามันเป็นธรรมชาติมากขึ้นที่จะเข้าใจความไม่เท่าเทียมกันเมื่อ notated L1[i]/2 <= L2[i] <= 2*L1[i]เป็น
orlp

1
นอกจากนี้การจับคู่ไม่ใช่ความสัมพันธ์ที่เท่าเทียมกัน match(A, B)และmatch(B, C)ไม่ได้บ่งบอกถึงmatch(A, C)(เหมือนกันสำหรับสิ่งที่ตรงกันข้าม) ตัวอย่าง: การจับคู่ [1] และ [2], [2] และ [3] จับคู่ แต่ [1] และ [3] ทำไม่ได้ ในทำนองเดียวกัน [1,3] และ [3,1] ไม่ตรงกัน [3, 1] และ [2, 3] ไม่ตรงกัน แต่ [1, 3] และ [2, 3] จับคู่
orlp

คำตอบ:


7

2, 4, 10, 16, 31, 47, 76, 112, 168

สำหรับแต่ละ n โค้ด Java นี้จะกำหนดอาร์เรย์การนับที่เป็นไปได้จากนั้นหาชุดที่ไม่เพิ่มขนาดที่ตรงกันสำหรับแต่ละขนาดเริ่มต้นด้วยชุดแบบสุ่มและปรับปรุงโดยการโคตรแบบลาดชันแบบสุ่ม ในแต่ละขั้นตอนหนึ่งในองค์ประกอบของชุดจะถูกเลือกแบบสุ่มและแทนที่ด้วยอาร์เรย์อื่นที่สุ่มเลือกอย่างสม่ำเสมอในบรรดาองค์ประกอบที่ไม่ได้ใช้งาน ขั้นตอนนี้ได้รับการยอมรับหากไม่เพิ่มจำนวนการแข่งขัน ใบสั่งหลังนี้ดูเหมือนจะสำคัญ การยอมรับขั้นตอนเฉพาะในกรณีที่พวกเขาลดจำนวนการแข่งขันไม่ได้ผลเท่าที่ควร ขั้นตอนที่เหลือจำนวนการแข่งขันคงที่อนุญาตให้มีการสำรวจพื้นที่การค้นหาและในที่สุดบางพื้นที่อาจเปิดขึ้นเพื่อหลีกเลี่ยงหนึ่งในการแข่งขัน หลังจาก 2 ^ 24 ขั้นตอนโดยไม่มีการปรับปรุงขนาดก่อนหน้านี้จะถูกส่งออกสำหรับมูลค่าปัจจุบันของ n และ n จะเพิ่มขึ้น

ผลลัพธ์สูงสุด n = 9 คือ2, 4, 10, 16, 31, 47, 76, 112, 168ปรับปรุงผลลัพธ์ก่อนหน้าสำหรับ n = 8 โดยหนึ่งและสำหรับ n = 9 คูณสอง สำหรับค่าที่สูงกว่าของ n ขีด จำกัด ของ 2 ^ 24 ขั้นตอนอาจต้องเพิ่มขึ้น

ฉันยังลองจำลองการหลอม (ด้วยจำนวนแมตช์เป็นพลังงาน) แต่ไม่มีการปรับปรุงจากการลงทางชัน

รหัส

บันทึกเป็นQuestion54354.java
รวบรวมกับjavac Question54354.java
ทำงานด้วยjava Question54354

import java.util.Arrays;
import java.util.HashSet;
import java.util.Random;
import java.util.Set;

public class Question54354 {
    static class Array {
        int [] arr;

        public Array (int [] arr) {
            this.arr = arr;
        }

        public int hashCode () {
            return Arrays.hashCode (arr);
        }

        public boolean equals (Object o) {
            return Arrays.equals (((Array) o).arr,arr);
        }
    }

    static int [] indices;
    static int [] [] counts;
    static boolean [] used;

    static Random random = new Random (0);

    static boolean match (int [] c1,int [] c2) {
        for (int k = 0;k < c1.length;k++)
            if (c1 [k] > 2 * c2 [k] || c2 [k] > 2 * c1 [k])
                return false;
        return true;
    }

    static int matches (int i) {
        int result = 0;
        for (int j = 0;j < indices.length;j++)
            if (j != i && match (counts [indices [i]],counts [indices [j]]))
                result++;
        return result;
    }

    static void randomize (int i) {
        do
            indices [i] = random.nextInt (counts.length);
        while (used [indices [i]]);
    }

    public static void main (String [] args) {
        for (int n = 1,length = 1;;n++,length += 2) {
            int [] lookup = new int [1 << n];
            for (int string = 0;string < 1 << n;string++)
                for (int bit = 1;bit < 1 << n;bit <<= 1)
                    if ((string & bit) != 0)
                        lookup [string]++;
            Set<Array> arrays = new HashSet<Array> ();
            for (int string = 0;string < 1 << length;string++) {
                int [] count = new int [n];
                for (int i = 0;i < n;i++)
                    count [i] = lookup [(string >> i) & ((1 << n) - 1)];
                arrays.add (new Array (count));
            }
            counts = new int [arrays.size ()] [];
            int j = 0;
            for (Array array : arrays)
                counts [j++] = array.arr;
            used = new boolean [counts.length];

            int m;
            outer:
            for (m = 1;m <= counts.length;m++) {
                indices = new int [m];
                for (;;) {
                    Arrays.fill (used,false);
                    for (int i = 0;i < m;i++) {
                        randomize (i);
                        used [indices [i]] = true;
                    }
                    int matches = 0;
                    for (int i = 0;i < m;i++)
                        matches += matches (i);
                    matches /= 2;
                    int stagnation = 0;
                    while (matches != 0) {
                        int k = random.nextInt (m);
                        int oldMatches = matches (k);
                        int oldIndex = indices [k];
                        randomize (k);
                        int newMatches = matches (k);
                        if (newMatches <= oldMatches) {
                            if (newMatches < oldMatches) {
                                matches += newMatches - oldMatches;
                                stagnation = 0;
                            }
                            used [oldIndex] = false;
                            used [indices [k]] = true;
                        }
                        else
                            indices [k] = oldIndex;

                        if (++stagnation == 0x1000000)
                            break outer;
                    }
                    break;
                }
            }
            System.out.println (n + " : " + (m - 1));
        }
    }
}

1
เป็นการปรับปรุงที่ดีมาก!

11

2, 4, 10, 16, 31, 47, 76, 111, 166, 235

หมายเหตุ

ถ้าเราพิจารณากราฟGที่มีจุด0ที่จะnและขอบร่วมงานกับตัวเลขสองตัวที่จับคู่แล้วอำนาจเมตริกซ์ G^nมีจุด(x_0, ..., x_{n-1})รูปอำนาจคาร์ทีเซียน{0, ..., n}^nและขอบระหว่าง tuples จับคู่ กราฟที่น่าสนใจคือกราฟย่อยของG^n เกิดจากจุดยอดเหล่านั้นซึ่งสอดคล้องกับ "อาร์เรย์ที่นับได้" ที่เป็นไปได้

ดังนั้นภารกิจย่อยแรกคือการสร้างจุดยอดเหล่านั้น วิธีไร้เดียงสาระบุมากกว่าสตริงหรือคำสั่งของ2^{2n-1} 4^nแต่ถ้าเราแทนที่จะมองไปที่อาร์เรย์ของความแตกต่างครั้งแรกของอาร์เรย์นับที่เราพบว่ามีเพียง3^nความเป็นไปได้และจากความแตกต่างที่แรกที่เราสามารถอนุมานช่วงของค่าเริ่มต้นที่เป็นไปได้โดยการกำหนดว่าองค์ประกอบในความแตกต่างข้อที่ศูนย์ไม่น้อยกว่า0หรือ nมากกว่า

จากนั้นเราต้องการค้นหาชุดอิสระสูงสุด ฉันใช้ทฤษฎีบทหนึ่งและสองฮิวริสติก:

  • ทฤษฎีบท: ชุดอิสระสูงสุดของสหภาพที่แยกจากกันของกราฟคือการรวมกันของชุดอิสระสูงสุดของพวกเขา ดังนั้นถ้าเราแบ่งกราฟออกเป็นส่วนประกอบที่ไม่ได้เชื่อมต่อเราสามารถทำให้ปัญหาง่ายขึ้น
  • การวิเคราะห์พฤติกรรม: สมมติว่า(n, n, ..., n)จะอยู่ในชุดอิสระสูงสุด มีจำนวนจุดยอด{m, m+1, ..., n}^nที่ค่อนข้างใหญ่ซึ่งmเป็นจำนวนเต็มที่น้อยที่สุดซึ่งตรงกับn;(n, n, ..., n)รับประกันได้ว่าจะไม่มีการแข่งขันนอกกลุ่มนั้น
  • Heuristic: ใช้ความโลภในการเลือกจุดสุดยอดในระดับต่ำสุด

บนคอมพิวเตอร์ของฉันนี้พบ111สำหรับn=8ใน 16 วินาที166สำหรับn=9ในเวลาประมาณ 8 นาทีและ235สำหรับn=10ในประมาณ 2 ชั่วโมง

รหัส

บันทึกเป็นPPCG54354.javaคอมไพล์เป็นและทำงานเป็นjavac PPCG54354.javajava PPCG54354

import java.util.*;

public class PPCG54354 {
    public static void main(String[] args) {
        for (int n = 1; n < 20; n++) {
            long start = System.nanoTime();

            Set<Vertex> constructive = new HashSet<Vertex>();
            for (int i = 0; i < (int)Math.pow(3, n-1); i++) {
                int min = 0, max = 1, diffs[] = new int[n-1];
                for (int j = i, k = 0; k < n-1; j /= 3, k++) {
                    int delta = (j % 3) - 1;
                    if (delta == -1) min++;
                    if (delta != 1) max++;
                    diffs[k] = delta;
                }

                for (; min <= max; min++) constructive.add(new Vertex(min, diffs));
            }

            // Heuristic: favour (n, n, ..., n)
            Vertex max = new Vertex(n, new int[n-1]);
            Iterator<Vertex> it = constructive.iterator();
            while (it.hasNext()) {
                Vertex v = it.next();
                if (v.matches(max) && !v.equals(max)) it.remove();
            }

            Set<Vertex> ind = independentSet(constructive, n);
            System.out.println(ind.size() + " after " + ((System.nanoTime() - start) / 1000000000L) + " secs");
        }
    }

    private static Set<Vertex> independentSet(Set<Vertex> vertices, int dim) {
        if (vertices.size() < 2) return vertices;

        for (int idx = 0; idx < dim; idx++) {
            Set<Set<Vertex>> p = connectedComponents(vertices, idx);
            if (p.size() > 1) {
                Set<Vertex> ind = new HashSet<Vertex>();
                for (Set<Vertex> part : connectedComponents(vertices, idx)) {
                    ind.addAll(independentSet(part, dim));
                }
                return ind;
            }
        }

        // Greedy
        int minMatches = Integer.MAX_VALUE;
        Vertex minV = null;
        for (Vertex v0 : vertices) {
            int numMatches = 0;
            for (Vertex vi : vertices) if (v0.matches(vi)) numMatches++;
            if (numMatches < minMatches) {
                minMatches = numMatches;
                minV = v0;
            }
        }

        Set<Vertex> nonmatch = new HashSet<Vertex>();
        for (Vertex vi : vertices) if (!minV.matches(vi)) nonmatch.add(vi);
        Set<Vertex> ind = independentSet(nonmatch, dim);
        ind.add(minV);
        return ind;
    }

    // Separates out a set of vertices which form connected components when projected into the idx axis.
    private static Set<Set<Vertex>> connectedComponents(Set<Vertex> vertices, final int idx) {
        List<Vertex> sorted = new ArrayList<Vertex>(vertices);
        Collections.sort(sorted, new Comparator<Vertex>() {
                public int compare(Vertex a, Vertex b) {
                    return a.x[idx] - b.x[idx];
                }
            });

        Set<Set<Vertex>> connectedComponents = new HashSet<Set<Vertex>>();
        Set<Vertex> current = new HashSet<Vertex>();
        int currentVal = 0;
        for (Vertex v : sorted) {
            if (!match(currentVal, v.x[idx]) && !current.isEmpty()) {
                connectedComponents.add(current);
                current = new HashSet<Vertex>();
            }

            current.add(v);
            currentVal = v.x[idx];
        }

        if (!current.isEmpty()) connectedComponents.add(current);
        return connectedComponents;
    }

    private static boolean match(int a, int b) {
        return a <= 2 * b && b <= 2 * a;
    }

    private static class Vertex {
        final int[] x;
        private final int h;

        Vertex(int[] x) {
            this.x = x.clone();

            int _h = 0;
            for (int xi : x) _h = _h * 37 + xi;
            h = _h;
        }

        Vertex(int x0, int[] diffs) {
            x = new int[diffs.length + 1];
            x[0] = x0;
            for (int i = 0; i < diffs.length; i++) x[i+1] = x[i] + diffs[i];

            int _h = 0;
            for (int xi : x) _h = _h * 37 + xi;
            h = _h;
        }

        public boolean matches(Vertex v) {
            if (v == this) return true;
            if (x.length != v.x.length) throw new IllegalArgumentException("v");
            for (int i = 0; i < x.length; i++) {
                if (!match(x[i], v.x[i])) return false;
            }
            return true;
        }

        @Override
        public int hashCode() {
            return h;
        }

        @Override
        public boolean equals(Object obj) {
            return (obj instanceof Vertex) && equals((Vertex)obj);
        }

        public boolean equals(Vertex v) {
            if (v == this) return true;
            if (x.length != v.x.length) return false;
            for (int i = 0; i < x.length; i++) {
                if (x[i] != v.x[i]) return false;
            }
            return true;
        }

        @Override
        public String toString() {
            if (x.length == 0) return "e";

            StringBuilder sb = new StringBuilder(x.length);
            for (int xi : x) sb.append(xi < 10 ? (char)('0' + xi) : (char)('A' + xi - 10));
            return sb.toString();
        }
    }
}

10

Mathematica n = 5,, 31 สาย

ฉันเพิ่งเขียนคำตอบที่โหดร้ายโดยใช้บิวด์อิน Mathematica เพื่อตรวจสอบคำตอบตัวอย่างของ Lembik แต่สามารถจัดการได้n = 5เช่นกัน:

n = 5;
s = Tuples[{0, 1}, 2 n - 1];
l = Total /@ Partition[#, n, 1] & /@ s
g = Graph[l, 
  Cases[Join @@ Outer[UndirectedEdge, l, l, 1], 
   a_ <-> b_ /; 
    a != b && And @@ Thread[a <= 2 b] && And @@ Thread[b <= 2 a]]]
set = First@FindIndependentVertexSet[g]
Length@set

เป็นโบนัสรหัสนี้สร้างภาพของปัญหาเป็นกราฟที่แต่ละขอบบ่งชี้สองสายที่ตรงกัน

นี่คือกราฟสำหรับn = 3:

ป้อนคำอธิบายรูปภาพที่นี่


2
ตอนแรกฉันคิดว่ากราฟนั้นสมมาตรกัน แต่จากนั้นฉันเห็นจุดออฟเซ็ตเล็กน้อยทางซ้าย ไม่สามารถยกเลิก :(
orlp

3

C ++ (การวิเคราะห์พฤติกรรม): 2, 4, 10, 16, 31, 47, 75, 111, 164, 232, 328, 445, 606, 814, 1086

นี่คือสิ่งที่อยู่เบื้องหลังผลลัพธ์ของ Peter Taylor เล็กน้อยสำหรับn=71 9และ103 nข้อดีก็คือว่ามันได้เร็วขึ้นมากดังนั้นฉันสามารถเรียกใช้ค่าที่สูงขึ้นของ และสามารถเข้าใจได้โดยไม่ต้องมีคณิตศาสตร์แฟนซี ;)

n=15รหัสปัจจุบันเป็นมิติที่จะวิ่งขึ้นไป เวลารันเพิ่มขึ้นประมาณ 4 เท่าสำหรับการเพิ่มแต่ละnครั้ง ตัวอย่างเช่นมันคือ 0.008 วินาทีสำหรับn=70.07 วินาทีสำหรับn=9, 1.34 วินาทีn=11, 27 วินาทีn=13และ 9 นาทีn=15นาที

มีข้อสังเกตสำคัญสองข้อที่ฉันใช้:

  • แทนที่จะจัดการกับค่าด้วยตนเองฮิวริสติกทำงานกับการนับอาร์เรย์ เมื่อต้องการทำเช่นนี้จะมีการสร้างรายการอาร์เรย์การนับที่ไม่ซ้ำกันทั้งหมดก่อน
  • การใช้อาร์เรย์การนับที่มีค่าน้อยจะมีประโยชน์มากกว่าเนื่องจากจะช่วยลดพื้นที่การแก้ปัญหาให้น้อยลง สิ่งนี้จะขึ้นอยู่กับการนับแต่ละครั้งcไม่รวมช่วงของc / 2ถึง2 * cจากค่าอื่น ๆ สำหรับค่าที่น้อยลงของcช่วงนี้จะเล็กกว่าซึ่งหมายความว่าจะมีการยกเว้นค่าน้อยลงโดยใช้มัน

สร้างอาร์เรย์การนับที่ไม่ซ้ำกัน

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

นี่เป็นสิ่งที่รวดเร็วอย่างยิ่งสำหรับค่าขนาดเล็ก สำหรับค่าที่มากขึ้นค่าโสหุ้ยจะกลายเป็นรูปธรรม ตัวอย่างเช่นสำหรับn=15ใช้ประมาณ 75% ของรันไทม์ทั้งหมด นี่จะเป็นพื้นที่ที่ควรพิจารณาเมื่อพยายามจะสูงกว่าn=15มาก แม้เพียงแค่การใช้หน่วยความจำสำหรับสร้างรายการของอาร์เรย์การนับสำหรับค่าทั้งหมดจะเริ่มมีปัญหา

จำนวนของอาร์เรย์การนับที่ไม่ซ้ำกันคือประมาณ 6% ของจำนวนค่า n=15ของจำนวนค่าสำหรับ จำนวนสัมพัทธ์นี้จะเล็กลงเมื่อnใหญ่ขึ้น

การเลือกโลภของการนับค่าอาร์เรย์

ส่วนหลักของอัลกอริทึมเลือกการนับค่าอาร์เรย์จากรายการที่สร้างขึ้นโดยใช้วิธีการโลภที่เรียบง่าย

ตามทฤษฎีที่ใช้การนับอาร์เรย์ที่มีจำนวนน้อยจะเป็นประโยชน์อาร์เรย์การนับจะเรียงลำดับตามผลรวมของการนับของพวกเขา

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

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

รหัส

สิ่งนี้ไม่ได้รับการปรับให้เหมาะสมอย่างมาก ฉันมีโครงสร้างข้อมูลที่ซับซ้อนมากขึ้นในบางจุด แต่มันจะต้องมีการทำงานมากขึ้นในการพูดเกินn=8จริงและความแตกต่างของประสิทธิภาพดูเหมือนจะไม่สำคัญนัก

#include <cstdint>
#include <cstdlib>
#include <vector>
#include <algorithm>
#include <sstream>
#include <iostream>

typedef uint32_t Value;

class Counter {
public:
    static void setN(int n);

    Counter();
    Counter(Value val);

    bool operator==(const Counter& rhs) const;
    bool operator<(const Counter& rhs) const;

    bool collides(const Counter& other) const;

private:
    static const int FIELD_BITS = 4;
    static const uint64_t FIELD_MASK = 0x0f;

    static int m_n;
    static Value m_valMask;

    uint64_t fieldSum() const;

    uint64_t m_fields;
};

void Counter::setN(int n) {
    m_n = n;
    m_valMask = (static_cast<Value>(1) << n) - 1;
}

Counter::Counter()
  : m_fields(0) {
}

Counter::Counter(Value val) {
    m_fields = 0;
    for (int k = 0; k < m_n; ++k) {
        m_fields <<= FIELD_BITS;
        m_fields |= __builtin_popcount(val & m_valMask);
        val >>= 1;
    }
}

bool Counter::operator==(const Counter& rhs) const {
    return m_fields == rhs.m_fields;
}

bool Counter::operator<(const Counter& rhs) const {
    uint64_t lhsSum = fieldSum();
    uint64_t rhsSum = rhs.fieldSum();
    if (lhsSum < rhsSum) {
        return true;
    }
    if (lhsSum > rhsSum) {
        return false;
    }

    return m_fields < rhs.m_fields;
}

bool Counter::collides(const Counter& other) const {
    uint64_t fields1 = m_fields;
    uint64_t fields2 = other.m_fields;

    for (int k = 0; k < m_n; ++k) {
        uint64_t c1 = fields1 & FIELD_MASK;
        uint64_t c2 = fields2 & FIELD_MASK;

        if (c1 > 2 * c2 || c2 > 2 * c1) {
            return false;
        }

        fields1 >>= FIELD_BITS;
        fields2 >>= FIELD_BITS;
    }

    return true;
}

int Counter::m_n = 0;
Value Counter::m_valMask = 0;

uint64_t Counter::fieldSum() const {
    uint64_t fields = m_fields;
    uint64_t sum = 0;
    for (int k = 0; k < m_n; ++k) {
        sum += fields & FIELD_MASK;
        fields >>= FIELD_BITS;
    }

    return sum;
}

typedef std::vector<Counter> Counters;

int main(int argc, char* argv[]) {
    int n = 0;
    std::istringstream strm(argv[1]);
    strm >> n;

    Counter::setN(n);

    int nBit = 2 * n - 1;
    Value maxVal = static_cast<Value>(1) << nBit;

    Counters allCounters;

    for (Value val = 0; val < maxVal; ++val) {
        Counter counter(val);
        allCounters.push_back(counter);
    }

    std::sort(allCounters.begin(), allCounters.end());

    Counters::iterator uniqEnd =
        std::unique(allCounters.begin(), allCounters.end());
    allCounters.resize(std::distance(allCounters.begin(), uniqEnd));

    Counters solCounters;
    int nSol = 0;

    for (Value idx = 0; idx < allCounters.size(); ++idx) {
        const Counter& counter = allCounters[idx];

        bool valid = true;
        for (int iSol = 0; iSol < nSol; ++iSol) {
            if (solCounters[iSol].collides(counter)) {
                valid = false;
                break;
            }
        }

        if (valid) {
            solCounters.push_back(counter);
            ++nSol;
        }
    }

    std::cout << "result: " << nSol << std::endl;

    return 0;
}

ฉันมีโซลูชันแบบเรียกซ้ำโดยอ้างอิงจากรหัสที่คล้ายกันซึ่งรับประกันว่าจะได้ประโยชน์สูงสุด แต่มันใช้เวลาสักพักn=4แล้ว มันอาจจะเสร็จสิ้นn=5ด้วยความอดทน n=7คุณต้องมีการใช้กลยุทธ์การย้อนรอยดีกว่าที่จะได้ให้ไป ฮิวริสติกของคุณหรือสำรวจพื้นที่โซลูชันทั้งหมดหรือไม่ ฉันใคร่ครวญแนวคิดบางอย่างเกี่ยวกับวิธีทำให้ดีขึ้นทั้งโดยการปรับแต่งการเรียงลำดับหรืออาจจะไม่โลภอย่างหมดจด
Reto Koradi

ความเข้าใจของฉันคือว่าไม่มีคำตอบในคำตอบของ Peter Taylor มันเป็นความโลภอย่างหมดจด เทคนิคหลักคือเขาลดจำนวนการนับอาร์เรย์3^nและสองฮิวริสติกที่เขาอธิบาย

@Lembik ความคิดเห็นของฉันตอบกลับความคิดเห็นที่ถูกลบไปแล้ว จำนวนของอาร์เรย์การนับควรเท่ากันเนื่องจากฉันสร้างที่ขึ้นอยู่กับค่าจริงและลดให้เหลือเฉพาะอาร์เรย์ที่ไม่ซ้ำกัน ฉันอัปเดตอัลกอริทึมเวอร์ชันย้อนรอย แม้ว่ามันจะไม่ยุติภายในเวลาอันสมควร แต่ก็พบว่า 76 สำหรับn=7ได้อย่างรวดเร็ว แต่ลองใช้n=9มันยังคงติดอยู่ที่ 164 เมื่อฉันหยุดมันหลังจาก 20 นาที ดังนั้นการขยายภาพย้อนหลังด้วยรูปแบบที่ จำกัด ของการย้อนรอยอย่างง่ายจึงไม่ได้มีแนวโน้ม
Reto Koradi
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.