... J'ai cherché quelques modèles pour construire une réduction à partir d'un problème de PNJ, mais je n'ai pas trouvé un moyen de représenter un "flux" avec un "fork" ...
Donc (après quelques travaux) c'est un algorithme polynomial ...
ALGORITHME
La liste de départ peut être vue comme un tableau de " trous " consécutifs . Pour chaque paire initiale ( a j , b j ) , mettez "l' élément " b j au numéro de trou a j . Chaque paire peut être considérée comme un bord dirigé de la position a j à la position b j . Un mouvement consiste à ramasser un élément b j à la position a j et à le déplacer vers sa position de destination b jN∗ 2( unj,bj)bjajajbjbjajbj(le trou de destination devient une cheville inamovible ). Nous supprimons l'arête et choisissons le mouvement suivant qui commencera à partir de l'un des deux éléments accessibles les plus proches depuis la position b j (seuls les trous entre b j et b k sont autorisés). Il faut trouver une séquence de N coups consécutifs.bkbjbjbkN
Lorsque vous effectuez un mouvement, vous fixez une cheville à la position et le tableau est divisé en deux partitions L (gauche) et R (droite) et la seule façon de passer de L à R (ou de R à L ) est d'utiliser un bord qui saute à travers la cheville. EnsemblebjLRLRRL
- = nombre d'arêtes de gauche à droite (ne pas compter l'arête finale)edgesLR
- = nombre d'arêtes de droite à gauche (sans compter l'arête finale)edgesRL
- = e d g e s L R - e d g e s R LflowedgesLR−edgesRL
Cas:
A) si puis l'une des deux partitions deviendra inaccessible, arrêtez|flow|>1
Supposons maintenant que , c'est-à-dire e n d ∈ Rend>bjend∈R
B) si alors il y a un bord supplémentaire de gauche à droite, vous devez aller à gauche (choisir l'élément le plus proche de L ), sinon vous n'atteindrez jamais e n dflow=1Lend
C) si alors il y a un bord supplémentaire de droite à gauche et quel que soit le nœud que vous choisissez, vous n'atteindrez jamais e n d , arrêtezflow=−1end
D) si vous devez aller à droite (choisir l'élément le plus proche de R ), sinon vous n'atteindrez jamais e n dflow=0Rend
Si ( e n d ∈ L ), B, C, D sont inversés.end<bjend∈L
REMARQUE: lorsque vous vous déplacez vers la gauche ou la droite, vous devez considérer comme une cheville. Par exemple, si vous devez aller à droite, mais l'élément le plus proche sur R est e n d alors le mouvement est impossible (et vous devez procéder avec une autre paire ( s t a r t , e n d ) )endRend(start,end)
Appliquez la même résonance à chaque mouvement.
COMPLEXITÉ
Les flux sur chaque trou peuvent être précalculés en O (N) et réutilisés à chaque balayage.
Les boucles sont:
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
Aucun choix n'est fait lors du calcul, donc la complexité de l'algorithme est O(N3)
CODE
Il s'agit d'une implémentation Java fonctionnelle de l'algorithme:
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);
}
}