Aşağıdaki problemde polinom zamanında bir sekans olup olmadığını bulmak mümkün müdür?


27

Bir süredir aşağıdaki problemi düşünüyordum ve bunun için bir polinom çözümü bulamadım. Sadece kaba-kırk. NP-Complete problemini de başarı ile azaltmaya çalışıyorum.

İşte sorun :


Bir var sıralı kümesi pozitif tamsayılar çiftlerinin. {(A1,B1),(A2,B2),,(An,Bn)}

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

Aşağıdaki işlem, bir çift uygulanabilir: Swap(pair). Çiftin elemanlarını değiştirir, böylece olur(10,50)(50,10)

Kümedeki bir çift değiştirildiğinde, küme otomatik olarak yeniden sıralanır (değiştirilen çift yerinde değildir ve kümedeki yerine taşınır).

Sorun, bazı çiftlerden başlayarak tüm koşulu aşağıdaki koşullarla değiştiren bir dizi olup olmadığına bakın:

Bir çiftin değiştirilmesinden sonra, değiştirilecek bir sonraki çift, kümedeki halefi veya öncül çift olmalıdır.


Bu soruna polinom zaman çözümü ya da NP-Komple sorununun azaltılması harika olurdu.

Not:
Bu zaten bir karar sorunu. Hangi dizinin olduğunu bilmek istemiyorum: sadece bir dizi varsa.

Bir çift değiştirildikten sonra setin nasıl sıralandığına örnek

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

İlk çifti değiştirirsem, şöyle olur: ve kümeyi sıraladıktan sonra (sıralanmış çifti yeni konumuna getirdikten sonra):(5,6)

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

Sonra (selef) çift veya (ardıç) değiştirmeliyim ve tüm çiftler değiştirilinceye kadar (mümkünse) işlemi tekrar etmeliyim.( 7 , 8 )(3,4)(7,8)

Önemli:
Önceden değiştirilmiş bir çifti değiştiremezsiniz.
Bir 'takas' işlemi dizisi varsa, tüm çiftlerin bir kez ve sadece bir kez yeniden adlandırılması gerekir.

Tüm çiftleri değiştirmenin mümkün olmadığı bir örnek

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


1
Liste, dosyayı yeniden adlandırdıktan sonra ve yeniden adlandırılacak bir sonraki dosyayı seçmeden önce sıralanıyor mu? Sıralama koşulunu şu şekilde yeniden yazabilir misiniz: iff ( ) veya ( ve ) veya ( ve ve )? A < A A = A B < B A = A B = B C < C (A,B,C)<(A,B,C)A<AA=AB<BA=AB=BC<C
mjqxxxx

3
Genel olarak cstheory.stackexchange.com adresinde atama sorunları kabul edilmez.
Tsuyoshi Ito

3
Hmm, emin değilim. Genellikle buradaki mantık, tipik ev ödevi sorularını cevaplamanın iyi bir uygulama olmadığıdır, çünkü bunu yapmak gelecekte birisinin ev ödevinin amacını mahvedecektir. Ancak bu durumda, sorun tipik bir soruna benzemiyor .
Tsuyoshi Ito

2
belki "bir ev ödeviydi" den farklı bir motivasyon verirseniz, insanlar ilgilenebilir ve kapanmaz. Bunun olası bir uygulaması ne olabilir?
Marcos Villagra

2
Sorunu yeniden düzenleme hakkında, dosyaları unutabilir ve bu şekilde görebilirsiniz. bir çift pozitif tamsayı ve kurallar sizin belirttiğiniz şekilde aynı. Başlangıçta ilk sütunda sıralanır, ardından noktaları yeniden adlandırmaya başlarsınız. A={(x1,y1),,(xn,yn)}
Marcos Villagra

Yanıtlar:


16

... bir NPC probleminden bir düşüş oluşturmak için bazı desenler aradım, ancak “çatal” ile “akış” ı temsil etmenin bir yolunu bulamadım ...

Yani (bazı işten sonra) bu polinom bir algoritma ...

ALGORITMASı

Başlangıç ​​listesi, ardışık " delikler " dizisi olarak görüntülenebilir . Her başlangıç ​​çifti için , " element " delik numarasına . Her çift konumundan konumuna yönlendirilmiş bir kenar olarak . Bir hareket , pozisyonunda elemanının ve onu hedef pozisyonuna hareket ettirmekten (hedef deliği mandal haline gelir ). Kenarı siliyoruz ve en yakın ulaşılabilir iki unsurdan birinden başlayacak olan sonraki hareketi seçmeye devam ediyoruz.( a j , b j ) b j a j a j b j b j a j b j b k b j b j b k NN2(aj,bj)bjajajbjbjajbjbk , (sadece ve arasındaki deliklere izin verilir). ardışık hamle dizisini bulmalıyız .bjbjbkN

  • Her biri için dikkate (dizi pozisyonda başlangıç elemanı olarak) .(aj,bj)bjajstart

    • Her biri için final elementin olarak kabul ( pozisyonundan pozisyonuna kadar olan kenar son kenar olacaktır).(ak,bk),akajakendakbk

      • elemanın ulaşana kadar (ve bir çözüm bulundu) ya da bir durma koşulu gelinceye kadar, aşağıdaki kriterleri kullanarak bir dizi hamle üretstartend

Bir hamle, pozisyon bir PEG saptamak ve dizi iki bölüm içinde ayrılmıştır olduğunu (sol) ve (sağ) ve gitmek için tek yol için (veya için ) bir kenar kullanıyor mandalın karşısındaki zıplama. setbjLRLRRL

  • edgesLR = soldan sağa olan kenarların sayısı (son kenarı )
  • edgesRL = sağdan sola doğru kenar sayısı (son kenarı sayma)
  • flow =edgesLRedgesRL

Durumlar:

A) eğer sonra iki bölümden birine ulaşılamaz hale gelecektir.|flow|>1

Şimdi bu , yaniend>bjendR

B) eğer ise soldan sağa ekstra bir kenar varsa, sola gitmelisin ( nin en yakın elemanını seç ), aksi takdirde aslaflow=1Lend

C) eğer ise sağdan sola doğru fazladan bir kenar vardır ve seçtiğiniz düğüm hiçbir zaman ,flow=1end

Eğer D) doğru gitmek gerekir (en yakın eleman almak aksi takdirde ulaşmak neve olacak)flow=0Rend

Eğer ( ), B, C, D ters çevrilir.end<bjendL

NOT: sola veya sağa hareket ederken, mandal olarak düşünmelisiniz . Örneğin, doğru gitmek gerekir, ama en yakın eleman eğer olduğunu sonra hareket imkansızdır (ve başka bir çift yürütülmesi gerektiğini )endRend(start,end)

Her harekette aynı rezonansı uygulayın.

KOMPLEKSLİĞİ

Her deliğin üzerindeki akışlar O (N) cinsinden önceden hesaplanabilir ve her taramada tekrar kullanılabilir.

Döngüler:

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     

Hesaplama sırasında hiçbir seçim yapılmadığından algoritmanın karmaşıklığıO(N3)

KOD

Bu, algoritmanın çalışan bir Java uygulamasıdır:

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);
    }    
}

Bu ilginç bir yaklaşım. Genel olarak, bir kenar , her bir yönde geçen eşit olmayan (ya da bir tane farklı) kullanılmamış kenarların sayısı olmalıdır ; ve sayılar bir farklılık gösterirse, hangi kenara geçmeniz gerektiğini bilirsiniz. Rakamlar eşit olduğunda, her iki seçeneği de test ederek çözmeniz gereken bir seçeneğiniz vardır. Yeterince verimli bir arama stratejisi gibi görünüyor, ancak en kötü durumda polinom olduğunu nasıl biliyorsunuz? Yani, sadece her bir yöndeki kullanılmayan geçiş kenarı sayısının eşit olduğu seçenekleriyle karşılaşacağınızı nasıl biliyorsunuz ? (a,b)bO(logn)
mjqxxxx

@mjqxxxx ... Java algoritmasına uyması için tüm cevabı yeniden yazdım ...
Marzio De Biasi

@mjqxxxx ... tamam, sonunda anladım ... :-)
Marzio De Biasi

2
Bu bana doğru ve çok zarif görünüyor. Bir kenar , artık boyunca "yürüyemezsiniz" ; boyunca kalan tek geçişler , kullanmanız gereken, kullanılmayan "atlar" (yönlendirilmiş kenarlar). Nihai kenarı ise belirtilirse, daha sonra aynı tarafında rüzgar gereken olarak . Daha sonra her kenardan sonra yürümek için tek bir yön vardır, çünkü başlangıçta yürüdüğünüz zıt (aynı) tarafta bir tek (çift) atlama sayısı sizi bırakacaktır. Böylece başlangıç ​​ve bitiş kenarlarının her birinin seçimi polinom zamanında yapılabilir. (a,b)bb(an,bn)ban
mjqxxxx

1
Bu güzel bir algoritma. Önce son hareketi düzeltmek benim başıma gelmedi. Küçük puanlar: (1) mjqxxxx'un yazdığı gibi, sonu a_k olmalıdır. Aksi halde “end> b_j” koşulu yanlıştır. (2) “Akış” tanımı ya ihmal edilmeli ya da B ve C durumları değiştirilmelidir.
Tsuyoshi Ito

10

Bu bir çözüm değil, takas ve sıralama işlemlerinden açıkça bahsedilmesini önleyen bir yeniden düzenlemedir. Tüm dosya adları listesini ve değiştirilen sürümlerini sıralayarak başlayın ve her bir dosya adını bu listedeki dizini ile tanımlayın. Daha sonra, aralarındaki tüm eski dosya adları zaten yok edilmişse ve aralarındaki yeni dosya adlarından hiçbiri henüz oluşturulmamışsa, iki dosya komşudur. Yenilenmiş sorun şudur:

Bir ayrık yönlendirilmiş kenarlar ile bir sipariş var bu kenarlardan öylen(a,b)a,b{1,2,,2n}(a1,b1),(a2,b2),...,(an,bn)

  • Eğer arasındadır ve , daha sonra veajbiai+1ji
  • Eğer arasındadır ve , daha sonra ?b i a i + 1 j i + 1bjbiai+1ji+1

2
+1. Bu eşdeğer sorunu belirtmek için çok daha basit bir yoldur. Sadece bir açıklama: Kenarlar (a, b) yönlendirilir (yani kenar (a, b) ve kenarın (b, a) farklı anlamları vardır).
Tsuyoshi Ito

@ Tsuyoshi: teşekkürler; 'Yönetti' demek için düzenleme yaptım.
mjqxxxx

Anladığım kadarıyla " , ile arasındadır " ifadesi, " " anlamına gelir . Bu yüzden sanırım sonuncusunu eski gösterimini değiştirmeye değer. a c a bacabc
Oleksandr Bondarenko

@Oleksandr: Burada “b, a ile c arasındadır”, “ya ​​<b <c veya c <b <a” anlamına gelir.
Tsuyoshi Ito
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.