Ist es möglich zu finden, ob eine Sequenz in Polynomialzeit in dem folgenden Problem existiert?


27

Ich habe eine Zeit lang über das folgende Problem nachgedacht und keine polynomielle Lösung dafür gefunden. Nur rohe Quelle. Ich habe versucht, ein NP-Complete-Problem ohne Erfolg zu reduzieren.

Hier ist das Problem :


Sie haben eine sortierte Menge positiver ganzzahliger Paare. {(A1,B1),(A2,B2),,(An,Bn)}

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

Die folgende Operation kann zu einem Paar angewendet werden: Swap(pair). Es tauscht die Elemente des Paares aus, sodass (10,50) zu (50,10)

Wenn ein Paar im Set getauscht wird, wird das Set automatisch erneut sortiert (das getauschte Paar ist nicht richtig platziert und wird an seinen Platz im Set verschoben).

Das Problem besteht darin, zu sehen, ob es eine Sequenz gibt, die, beginnend mit einem Paar, den gesamten Satz mit der folgenden Bedingung austauscht:

Nachdem ein Paar getauscht wurde, muss das nächste auszutauschende Paar entweder das Nachfolger- oder das Vorgängerpaar im Satz sein.


Es wäre großartig, eine polynomielle Zeitlösung für dieses Problem zu finden oder ein NP-vollständiges Problem darin zu reduzieren.

Hinweis:
Es ist bereits ein Entscheidungsproblem. Ich möchte nicht wissen, um welche Sequenz es sich handelt: Nur wenn eine Sequenz existiert.

Beispiel, wie das Set nach dem Tausch eines Paares sortiert wird

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

Wenn ich das erste Paar vertausche, wird es zu: , und nach dem Sortieren des Satzes (Platzieren des sortierten Paares an seiner neuen Position) haben wir:(5,6)

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

Dann muss ich entweder das (Vorgänger) Paar oder ( 7 , 8 ) (Nachfolger) tauschen und den Vorgang wiederholen, bis alle Paare getauscht sind (falls möglich).(3,4)(7,8)

Wichtig:
Ein bereits getauschtes Paar kann nicht getauscht werden.
Wenn es eine Folge von 'Swap'-Operationen gibt, müssen alle Paare einmal und nur einmal umbenannt werden.

Beispiel, bei dem nicht alle Paare getauscht werden können

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


1
Wird die Liste sortiert, nachdem Sie die Datei umbenannt und bevor Sie die nächste Datei zum Umbenennen auswählen? Können Sie die Sortierbedingung wie folgt umschreiben: iff ( A < A ' ) oder ( A = A ' und B < B ' ) oder ( A = A ' Und B = B ' und C < C '(A,B,C)<(A,B,C)A<AA=AB<BA=AB=BC<C)?
mjqxxxx

3
Zuweisungsprobleme sind auf cstheory.stackexchange.com im Allgemeinen nicht erwünscht.
Tsuyoshi Ito

3
Hmm, ich bin mir nicht sicher. Normalerweise ist die Logik hier, dass es keine gute Praxis ist, typische Hausaufgabenfragen zu beantworten, da dies den Zweck von Hausaufgaben für jemanden in der Zukunft ruinieren wird. In diesem Fall sieht das Problem jedoch nicht wie ein typisches Problem aus.
Tsuyoshi Ito

2
Wenn Sie eine andere Motivation angeben als "es war eine Hausaufgabe", könnten sich die Leute dafür interessieren und es wird nicht geschlossen. Was könnte eine mögliche Anwendung davon sein?
Marcos Villagra

2
Wenn Sie das Problem neu formulieren, können Sie Dateien vergessen und so sehen. Sie haben eine Reihe von Paaren positiver Ganzzahlen , und die Regeln stimmen mit Ihren Angaben überein. Wird zunächst in der ersten Spalte sortiert, beginnen Sie mit dem Umbenennen der Punkte. A={(x1,y1),,(xn,yn)}
Marcos Villagra

Antworten:


16

... Ich habe einige Muster durchsucht, um eine Reduktion aus einem NPC-Problem zu erstellen, habe aber keine Möglichkeit gefunden, einen "Fluss" mit einer "Gabel" darzustellen ...

Also (nach einiger Arbeit) ist dies ein Polynomalgorithmus ...

ALGORITHMUS

Die Startliste kann als Array von aufeinanderfolgenden " Löchern " angesehen werden. Setzen Sie für jedes Anfangspaar ( a j , b j ) das " Element " b j an Lochnummer a j . Jedes Paar kann als gerichtete Kante von Position a j bis Position b j betrachtet werden . Ein Zug besteht , ein Element in der Kommissionierung b j an Position a j und es zu seiner Zielposition zu bewegen b jN2(aj,bj)bjajajbjbjajbj(das Zielloch wird zum unmovable PEG ). Wir löschen die Kante und wählen den nächsten Zug, der von einem der beiden am nächsten erreichbaren Elemente ab Position b j beginnt (nur Löcher zwischen b j und b k sind zulässig). Wir müssen eine Folge von N aufeinanderfolgenden Zügen finden.bkbjbjbkN

  • Für jedes betrachte b j (an der Array-Position a j ) als das Startelement s t a r t .(aj,bj)bjajstart

    • Für jedes betrachten einen k als letztes Element e n d (die Kante von Position a k zur Position b k wird die letzte Kante sein).(ak,bk),akajakendakbk

      • Generieren Sie eine Folge von Bewegungen von mit den folgenden Kriterien, bis Sie das Element e n d erreichen (und eine Lösung gefunden wurde) oder eine Stoppbedingungstartend

Wenn Sie einen Schritt machen fixieren Sie einen Stift an Position und das Array ist in zwei Partitionen aufgeteilt L (links) und R (rechts) und den einzigen Weg aus zu gehen , L bis R (oder von R bis L ) einem unter Verwendung von Kante, die über den Stift springt. einstellenbjLRLRRL

  • = Anzahl der Kanten von links nach rechts (letzte Kante nicht mitzählen)edgesLR
  • = Anzahl der Kanten von rechts nach links (letzte Kante nicht mitzählen)edgesRL
  • = e d g e s L R - e d g e s R LflowedgesLRedgesRL

Fälle:

A) wenn wenn eine der beiden Partitionen nicht mehr erreichbar ist, stoppen Sie|flow|>1

Nehmen wir nun an, dass , dh e n d Rend>bjendR

B) Wenn dann gibt es eine zusätzliche Kante von links nach rechts, Sie müssen nach links gehen (wählen Sie das nächste Element von L ), sonst werden Sie nie e n d erreichenflow=1Lend

C) Wenn ist, gibt es eine zusätzliche Kante von rechts nach links, und welcher Knoten auch immer Sie auswählen, Sie werden niemals e n d erreichen , stoppen Sieflow=1end

D) Wenn , müssen Sie nach rechts gehen (wählen Sie das nächste Element von R ), andernfalls werden Sie e n d nicht erreichenflow=0Rend

end<bjendL

endRend(start,end)

Wenden Sie bei jeder Bewegung die gleiche Resonanz an.

KOMPLEXITÄT

Die Ströme über jedes Loch können in O (N) vorberechnet und bei jedem Scan erneut verwendet werden.

Die Schleifen sind:

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)

CODE

Dies ist eine funktionierende Java-Implementierung des Algorithmus:

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 ... Ich habe die gesamte Antwort umgeschrieben, um sie an den Java-Algorithmus anzupassen ...
Marzio De Biasi

@mjqxxxx ... ok, endlich habe ich es ... :-)
Marzio De Biasi

2
(a,b)bb(an,bn)ban. Es gibt dann nur eine mögliche Richtung, in die Sie nach jeder Kante gehen können, da Sie nach einer ungeraden (geraden) Anzahl von Sprüngen auf der gegenüberliegenden (gleichen) Seite zurückbleiben, zu der Sie ursprünglich gegangen sind. So kann jede Auswahl von Start- und Endkanten in Polynomzeit getestet werden.
mjqxxxx

1
Dies ist ein wunderschöner Algorithmus. Es ist mir nie in den Sinn gekommen, den letzten Zug zuerst zu korrigieren. Nebenpunkte: (1) Wie mjqxxxx schrieb, muss end a_k sein. Ansonsten ist die Bedingung "end> b_j" falsch. (2) Entweder muss die Definition von „Flow“ negiert werden, oder die Fälle B und C müssen vertauscht werden.
Tsuyoshi Ito

10

Dies ist keine Lösung, sondern eine Neuformulierung, die die explizite Erwähnung der Austausch- und Sortiervorgänge vermeidet. Sortieren Sie zunächst die gesamte kombinierte Liste der Dateinamen und ihrer ausgetauschten Versionen, und identifizieren Sie jeden Dateinamen mit seinem Index in dieser Liste. Dann sind zwei Dateien Nachbarn, wenn alle alten Dateinamen zwischen ihnen bereits zerstört wurden und noch keiner der neuen Dateinamen zwischen ihnen erstellt wurde. Das umformulierte Problem ist das folgende:

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

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

2
+1. Dies ist eine viel einfachere Möglichkeit, das entsprechende Problem anzugeben. Nur eine Klarstellung: Die Kanten (a, b) sind gerichtet (in dem Sinne, dass die Kante (a, b) und die Kante (b, a) unterschiedliche Bedeutungen haben).
Tsuyoshi Ito

@ Tsuyoshi: danke; Ich redigierte, um "verwiesen" zu sagen.
mjqxxxx

bacabc

@Oleksandr: Hier bedeutet "b ist zwischen a und c" "entweder a <b <c oder c <b <a".
Tsuyoshi Ito
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.