... Tôi đã tìm kiếm một số mẫu để tạo ra sự giảm bớt từ một vấn đề NPC, nhưng không tìm ra cách nào để thể hiện một "dòng chảy" bằng một "ngã ba" ...
Vì vậy (sau một số công việc) đây là một thuật toán đa thức ...
TIẾNG VIỆT
Danh sách bắt đầu có thể được xem như là một mảng của "liên tiếp lỗ ". Đối với mỗi cặp ban đầu ( a j , b j ) , đặt " phần tử " b j vào lỗ số a j . Mỗi cặp có thể được xem như một cạnh được định hướng từ vị trí a j đến vị trí b j . Một di chuyển bao gồm trong việc lựa chọn một yếu tố b j ở vị trí một j và di chuyển nó đến vị trí của nó đến b jN∗2(aj,bj)bjajajbjbjajbj(lỗ đích trở thành một chốt không thể di chuyển ). Chúng tôi xóa cạnh và tiến hành chọn bước tiếp theo sẽ bắt đầu từ một trong hai yếu tố có thể tiếp cận gần nhất từ vị trí b j (chỉ cho phép các lỗ giữa b j và b k ). Chúng ta phải tìm một chuỗi N di chuyển liên tiếp.bkbjbjbkN
Khi bạn thực hiện di chuyển, bạn sửa một chốt ở vị trí và mảng được chia thành hai phân vùng L (trái) và R (phải) và cách duy nhất để đi từ L đến R (hoặc từ R đến L ) là sử dụng một cạnh đó nhảy qua chốt. BộbjLRLRRL
- = số cạnh từ trái sang phải (không tính cạnh cuối cùng)edgesLR
- = số cạnh từ phải sang trái (không tính cạnh cuối cùng)edgesRL
- = e d g e s L R - e d g e s R LflowedgesLR−edgesRL
Các trường hợp:
A) nếu thì một trong hai phân vùng sẽ không thể truy cập được, dừng lại|flow|>1
Bây giờ giả sử rằng , tức là e n d ∈ Rend>bjend∈R
B) nếu thì có thêm một cạnh từ trái sang phải, bạn phải đi sang trái (chọn phần tử gần nhất của L ), nếu không bạn sẽ không bao giờ đạt được e n dflow=1Lend
C) nếu thì có thêm một cạnh từ phải sang trái và bất kỳ nút nào bạn chọn, bạn sẽ không bao giờ đạt được e n d , dừng lạiflow=−1end
D) nếu bạn phải đi đúng (chọn phần tử gần nhất của R ), nếu không bạn sẽ đạt được e n dflow=0Rend
Nếu ( e n d ∈ L ), B, C, D bị đảo ngược.end<bjend∈L
LƯU Ý: khi di chuyển sang trái hoặc phải, bạn phải coi là một chốt. Ví dụ: nếu bạn phải đi đúng, nhưng phần tử gần nhất trên R là e n d thì việc di chuyển là không thể (và bạn phải tiến hành với một cặp khác ( s t a r t , e n d ) )endRend(start,end)
Áp dụng cùng một quy hoạch lại ở mỗi di chuyển.
THÀNH PHẦN
Dòng chảy qua mỗi lỗ có thể được xác định trước trong O (N) và được sử dụng lại ở mỗi lần quét.
Các vòng lặp là:
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
Không có lựa chọn nào được thực hiện trong quá trình tính toán, vì vậy độ phức tạp của thuật toán là O(N3)
MÃ
Đây là một triển khai Java hoạt động của thuật toán:
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);
}
}