เป็นไปได้ไหมที่จะหาลำดับที่มีอยู่ในเวลาพหุนามในปัญหาต่อไปนี้


27

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

นี่คือปัญหา :


คุณมีชุดเรียงลำดับ{(A1,B1),(A2,B2),,(An,Bn)}ของคู่จำนวนเต็มบวก

(Ai,Bi)<(Aj,Bj)Ai<Aj(Ai=AjBi<Bj) (Ai,Bi)=(Aj,Bj)Ai=AjBi=Bj

การดำเนินการต่อไปนี้สามารถใช้กับคู่: Swap(pair). มันสลับองค์ประกอบของคู่ดังนั้น(10,50)จะกลายเป็น(50,10)

เมื่อมีการสลับคู่ในชุดนั้นชุดนั้นก็จะถูกจัดเรียงอีกครั้งโดยอัตโนมัติ (คู่ที่สลับนั้นจะออกนอกสถานที่และมันจะถูกย้ายไปที่ที่ตั้งในชุด)

ปัญหาประกอบด้วยเมื่อดูว่ามีลำดับที่เริ่มต้นในบางคู่แลกเปลี่ยนทั้งชุดโดยมีเงื่อนไขดังต่อไปนี้:

หลังจากสลับคู่แล้วคู่ถัดไปที่จะสลับจะต้องเป็นตัวตายตัวแทนหรือคู่ก่อนหน้าในชุด


มันจะเป็นการดีถ้าคุณหาวิธีแก้ปัญหาเวลาแบบพหุนามกับปัญหานี้หรือลดปัญหา NP-Complete ลงไป

หมายเหตุ:
มันเป็นปัญหาการตัดสินใจอยู่แล้ว ฉันไม่ต้องการที่จะรู้ว่าลำดับคือ: เฉพาะถ้ามีลำดับ

ตัวอย่างของวิธีการเรียงลำดับชุดหลังจากสลับคู่

(6, 5)
(1,2)
(3,4)
(7,8)

ถ้าฉันสลับคู่แรกมันจะกลายเป็น: (5,6)และหลังจากเรียงลำดับชุด (วางคู่ที่เรียงลำดับในตำแหน่งใหม่) เรามี:

(1,2)
(3,4)
(5,6)
(7,8)

จากนั้นฉันต้องสลับทั้งคู่ (รุ่นก่อน) หรือ( 7 , 8 ) (ตัวช่วย) และทำซ้ำกระบวนการจนกว่าคู่ทั้งหมดจะถูกสลับ (ถ้าเป็นไปได้)(3,4)(7,8)

สำคัญ:
คุณไม่สามารถสลับคู่ที่แลกเปลี่ยนแล้ว
หากมีการดำเนินการตามลำดับของ 'swap' ดังนั้นคู่ทั้งหมดจะต้องเปลี่ยนเป็นครั้งเดียว

ตัวอย่างที่ไม่สามารถสลับคู่ทั้งหมดได้

( 1 , 4 ) ( 3 , 2 ) ( 5 , 5 )(0,0)
(1,4)
(3,2)
(5,5)


1
รายการเรียงลำดับหลังจากคุณเปลี่ยนชื่อไฟล์และก่อนที่คุณจะเลือกไฟล์ถัดไปเพื่อเปลี่ยนชื่อหรือไม่ คุณสามารถเขียนเงื่อนไขการเรียงลำดับดังนี้ IFF ( < ' ) หรือ ( = 'และB < B ' ) หรือ ( = และB = B และC < C (A,B,C)<(A,B,C)A<AA=AB<BA=AB=BC<C)?
mjqxxxx

3
ปัญหาการมอบหมายไม่ได้รับการต้อนรับใน cstheory.stackexchange.com โดยทั่วไป
Tsuyoshi Ito

3
อืมฉันไม่แน่ใจ โดยทั่วไปแล้วเหตุผลที่นี่ไม่ใช่วิธีปฏิบัติที่ดีในการตอบคำถามการบ้านทั่วไปเพราะการทำเช่นนั้นจะทำลายจุดประสงค์ของการบ้านสำหรับใครบางคนในอนาคต แต่ในกรณีนี้ปัญหาดูไม่เหมือนปัญหาทั่วไป
Tsuyoshi Ito

2
บางทีถ้าคุณให้แรงบันดาลใจที่แตกต่างจาก "มันเป็นการบ้าน" ผู้คนอาจจะสนใจและมันจะไม่ถูกปิด สิ่งที่อาจเป็นไปได้ในการประยุกต์ใช้นี้
Marcos Villagra

2
คุณสามารถลืมเกี่ยวกับไฟล์และดูด้วยวิธีนี้ คุณมีชุดของจำนวนเต็มบวกและกฎเป็นเช่นเดียวกับที่คุณวางไว้ เริ่มแรกจะเรียงลำดับในคอลัมน์แรกจากนั้นคุณเริ่มเปลี่ยนชื่อจุด A={(x1,y1),,(xn,yn)}
Marcos Villagra

คำตอบ:


16

... ฉันค้นหารูปแบบบางอย่างเพื่อสร้างการลดลงจากปัญหา NPC แต่ไม่พบวิธีในการแสดง "flow" ด้วย "fork" ...

ดังนั้น (หลังจากที่ทำงาน) นี่คืออัลกอริทึมพหุนาม ...

ขั้นตอนวิธี

รายการเริ่มต้นสามารถดูเป็นอาร์เรย์ของติดต่อกัน " หลุม " สำหรับแต่ละคู่เริ่มต้น( J , J ) , ใส่ " องค์ประกอบ " ที่บ้านเลขที่หลุมเจ แต่ละคู่สามารถดูเป็นขอบกำกับจากตำแหน่งไปยังตำแหน่งที่ การย้ายประกอบด้วยการเลือกองค์ประกอบb jที่ตำแหน่งa jและย้ายไปยังตำแหน่งปลายทางb jN2(aj,bj)bjajajbjbjajbj(หลุมปลายทางกลายเป็นหมุดที่ถอดออกไม่ได้) เราลบขอบและดำเนินการเลือกการเคลื่อนไหวถัดไปซึ่งจะเริ่มต้นจากหนึ่งในสององค์ประกอบที่เข้าถึงได้ใกล้ที่สุดจากตำแหน่งb j (อนุญาตเฉพาะช่องระหว่างb jและb kเท่านั้น) เราจะต้องหาลำดับการเคลื่อนที่ต่อเนื่องNครั้งbkbjbjbkN

  • สำหรับแต่ละพิจารณาJ (ที่ตำแหน่งอาร์เรย์J ) เป็นองค์ประกอบเริ่มต้นs T R T(aj,bj)bjajstart

    • (ak,bk),akajakendakbk

      • startend

bjLRLRRL

  • edgesLR
  • edgesRL
  • flowedgesLRedgesRL

กรณี:

|flow|>1

end>bjendR

flow=1Lend

flow=1end

flow=0Rend

end<bjendL

endRend(start,end)

ใช้การ resoning เดียวกันทุกครั้ง

ซับซ้อน

กระแสที่ไหลผ่านแต่ละหลุมสามารถคำนวณได้ล่วงหน้าใน O (N) และนำมาใช้ซ้ำในทุกการสแกน

ลูปคือ:

for start = 1 to N
  for end = 1 to N
    for move = 1 to N
      make a move (fix a peg and update flows)
      check if another move can be done using flow     

O(N3)

รหัส

นี่เป็นการนำ Java ไปใช้งานของอัลกอริทึม:

public class StrangeSort {
    static int PEG = 0xffffff, HOLE = 0x0;
    static int M = 0, N = 0, choices = 0, aux = 0, end;
    static int problem[][], moves[], edgeflow[], field[];    
    boolean is_hole(int x) { return x == HOLE; }
    boolean is_peg(int x) { return x == PEG; }
    boolean is_ele(int x) { return ! is_peg(x) && ! is_hole(x); };
    int []cp(int src[]) { // copy an array
        int res[] = new int[src.length];
        System.arraycopy(src, 0, res, 0, res.length);
        return res;
    }    
    /* find the first element on the left (dir=-1) right (dir=1) */
    int find(int pos, int dir, int nm) {
        pos += dir;
        while (pos >= 1 && pos <= M ) {
            int x = field[pos];
            if ( is_peg(x) || (pos == end && nm < N-1) ) return 0;
            if ( is_ele(x) ) return pos;
            pos += dir;
        }
        return 0;
    }
    void build_edges() {
        edgeflow = new int[M+1];
        for (int i = 1; i<=M; i++) {
            int start = i;
            int b = field[start];
            if (! is_ele(b)) continue;
            if (i == end) continue;
            int dir = (b > start)? 1 : -1;
            start += dir;
            while (start != b) { edgeflow[start] += dir; start += dir; }
        }
    }
    boolean rec_solve(int start, int nm) {
        boolean f;
        int j;
        int b = field[start];
        moves[nm++] = b;
        if (nm == N) return true;
        //System.out.println("Processing: " + start + "->" + field[start]);        
        field[start] = HOLE;
        field[b] = PEG;
        int dir = (b > start)? 1 : -1;
        int i = start + dir;
        while (i != b) { edgeflow[i] -= dir; i += dir; } // clear edge                
        int flow = edgeflow[b];
        if (Math.abs(flow) > 2) return false;
        if (end > b) {
            switch (flow) {
            case 1 :                    
                j = find(b,-1,nm);
                if (j <= 0) return false;
                return rec_solve(j,nm);
            case -1 :
                return false;
            case 0 :          
                j = find(b,1,nm);
                if (j <= 0) return false;
                return rec_solve(j,nm);
            }        
        } else {
            switch (flow) {
            case -1 :                    
                j = find(b,1,nm);
                if (j <= 0) return false;
                return rec_solve(j,nm);
            case 1 :
                return false;
            case 0 :          
                j = find(b,-1,nm);
                if (j <= 0) return false;
                return rec_solve(j,nm);
            }            
        }
        return false;
    }
    boolean solve(int demo[][]) {
        N = demo.length;
        for (int i = 0; i < N; i++)
            M = Math.max(M, Math.max(demo[i][0], demo[i][1]));
        moves = new int[N];
        edgeflow = new int[M+1];
        field = new int[M+1];
        problem = demo;        
        for (int i = 0; i < problem.length; i++) {
            int a = problem[i][0];
            int b = problem[i][1];
            if ( a < 1 || b < 1 || a > M || b > M || ! is_hole(field[a]) || ! is_hole(field[b])) {
                System.out.println("Bad input pair (" + a + "," + b + ")");
                return false;
            }
            field[a] = b;
        }
        for (int i = 1; i <= M; i++) {
            end = i;
            build_edges();
            if (!is_ele(field[i])) continue;
            for (int j = 1; j <= M; j++) {
                if (!is_ele(field[j])) continue;
                if (i==j) continue;
                int tmp_edgeflow[] = cp(edgeflow);
                int tmp_field[] = cp(field);
                choices = 0;
                //System.out.println("START: " + j + " " + " END: " + i);
                if (rec_solve(j, 0)) {
                    return true;
                }
                edgeflow = tmp_edgeflow;
                field = tmp_field;
            }
        }
        return false;
    }
    void init(int demo[][]) {

    }
    public static void main(String args[]) {
        /**** THE INPUT ********/        

        int demo[][] =  {{4,2},{5,7},{6,3},{10,12},{11,1},{13,8},{14,9}};

        /***********************/        
        String r = "";
        StrangeSort sorter = new StrangeSort();       
        if (sorter.solve(demo)) {
            for (int i = 0; i < N; i++) { // print it in clear text
                int b =  moves[i];
                for (int j = 0; j < demo.length; j++)
                    if (demo[j][1] == b)
                        r += ((i>0)? " -> " : "") + "(" + demo[j][0] + "," + demo[j][1] + ")";
            }             
            r = "SOLUTION: "+r;
        }
        else
            r = "NO SOLUTIONS";
        System.out.println(r);
    }    
}

(a,b)bO(logn)

@mjqxxxx ... ฉันเขียนคำตอบทั้งหมดใหม่เพื่อให้ตรงกับอัลกอริทึม Java ...
Marzio De Biasi

@mjqxxxx ... ตกลงในที่สุดฉันก็ได้รับ ... :-)
Marzio De Biasi

2
(a,b)bb(an,bn)ban. มีทิศทางเดียวที่เป็นไปได้ที่จะเดินไปตามขอบแต่ละด้านเนื่องจากจำนวนการกระโดดที่แปลก (เท่า) จะทำให้คุณอยู่ฝั่งตรงข้าม (เดียวกัน) ที่คุณเริ่มเดินไป ดังนั้นการทดสอบทางเลือกของการเริ่มต้นและการสิ้นสุดของขอบสามารถทำได้ในเวลาพหุนาม
mjqxxxx

1
นี่เป็นอัลกอริธึมที่สวยงาม มันไม่เคยเกิดขึ้นกับฉันที่จะแก้ไขการเคลื่อนไหวครั้งสุดท้ายก่อน คะแนนย่อย: (1) ตามที่ mjqxxxx เขียนไว้ท้ายจะต้องเป็น a_k มิฉะนั้นเงื่อนไข“ สิ้นสุด> b_j” ไม่ถูกต้อง (2) คำจำกัดความของ“ flow” ต้องถูกทำให้เป็นโมฆะหรือกรณี B และ C ต้องสลับกัน
Tsuyoshi Ito

10

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

n(a,b)a,b{1,2,,2n}(a1,b1),(a2,b2),...,(an,bn)

  • ajbiai+1ji
  • bjbiai+1ji+1

2
+1 นี่เป็นวิธีที่ง่ายกว่ามากในการระบุปัญหาที่เทียบเท่ากัน การชี้แจงเพียงครั้งเดียว: ขอบ (a, b) ถูกชี้นำ (ในแง่ที่ว่าขอบ (a, b) และขอบ (b, a) มีความหมายต่างกัน)
Tsuyoshi Ito

@Tsuyoshi: ขอบคุณ; ฉันแก้ไขเพื่อบอกว่า 'กำกับ'
mjqxxxx

bacabc

@Oleksandr: ที่นี่“ b อยู่ระหว่าง a และ c” หมายถึง“ a <b <c หรือ c <b <a.”
Tsuyoshi Ito
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.