5-26 多轨车皮编序问题
问题描述
在一个列车调度站中,k 条轨道连接到 k 条侧轨处,形成 k 个铁路转轨栈,从左到右依次编号为 1,2,…,k。其中左边轨道为车皮入口,编号为 0;右边轨道为出口,编号为 k+1。 当 k=2 时,如下图所示。编号为 1,2,…,n 的 n 个车皮散乱地停放在编号为 0,1,2,…, k 的栈轨处。调度室要安排各车皮进出栈次序,使得在出口处各车皮按照其编号次序 1,2,…, n 依次出站。车皮移动时只能按照从左到右的方向移动。
给定车皮数 n 和侧轨数 k,以及各车皮的位置,编程计算最优调度方案,使得移动车皮 的总次数最少。
数据输入:
第一行有 2 个正整数 n 和 k,表示车皮数为 n 和侧轨数 为 k。接下来的 k+1 行中,表示编号为 0,1,2,…,k 的栈轨处按照从下到上的顺序停放 的车皮序列。每行的第一个数表示该栈轨处的车皮数,紧接着是车皮序列。
Java
package Chapter5HuiSuFa;
import java.util.Scanner;
public class DuoGuiChePiBianXu {
private static class Move{
int code;
int source;
int target;
}
private static int MAX = 10000;
private static int MAXSHORT = 10000;
private static int n,k;
private static int[] top;
private static int[][] sta;
private static int best;
private static int scount,gcount;
private static Move[] solu,opt;
public static void main(String[] args){
Scanner input = new Scanner(System.in);
while (true){
best = MAX;
n = input.nextInt();
k = input.nextInt();
top = new int[k+2];
sta = new int[k+2][n+1];
solu = new Move[MAX];
opt = new Move[MAX];
for(int i=0; i<=k; i++){
top[i] = input.nextInt();
for(int j=1; j<=top[i]; j++)
sta[i][j] = input.nextInt();
}
for(int i=1; i<n+1; i++)
sta[k+1][i] = i;
top[k+1] = 0;
sta[k][0] = n+1;
backtrack(0);
if(best == MAXSHORT)
System.out.println("No Solution!");
else {
System.out.println(best);
output(opt,best);
}
}
}
private static boolean moves(){
boolean t = true;
while (t){
t = false;
if(top[k+1] == n){
if(best > gcount){
best = gcount;
copyans(gcount);
}
scount++;
return true;
}
for(int i=0; i<=k; i++)
if(top[i]>0 && sta[i][top[i]]==sta[k+1][top[k+1]+1]){
move(i,k+1,++gcount);
t = true;
}
}
return false;
}
private static void move(int i, int j, int count){
solu[count] = new Move();
solu[count].code = sta[i][top[i]];
solu[count].source = i;
solu[count].target = j;
sta[j][top[j]+1] = sta[i][top[i]];
top[j]++; top[i]--;
}
private static void copyans(int k){
for(int i=1; i<=k; i++){
opt[i] = new Move();
opt[i].code = solu[i].code;
opt[i].source = solu[i].source;
opt[i].target = solu[i].target;
}
}
private static void backtrack(int count){
int[] stop = new int[k+2];
int[][] ssta = new int[k+2][n+1];
int count1;
gcount = count;
if(moves()) return;
save(ssta,stop);
count1 = gcount+1;
for(int i=0; i<k; i++)
for(int j=i+1; j<=k; j++)
if(top[i]>0 && (j<k || j==k&&sta[i][top[i]]<sta[j][top[j]])){
move(i,j,count1);
backtrack(count1);
restore(ssta,stop);
}
}
private static void save(int[][] a, int[] b){
for(int i=0; i<k+2; i++){
b[i] = top[i];
for(int j=0; j<=n; j++)
a[i][j] = sta[i][j];
}
}
private static void restore(int[][] a, int[] b){
for(int i=0; i<k+2; i++){
top[i] = b[i];
for(int j=0; j<=n; j++)
sta[i][j] = a[i][j];
}
}
private static void output(Move[] opt, int best){
for(int i=1; i<=best; i++)
System.out.println(opt[i].code+" "+opt[i].source+" "+opt[i].target);
}
}
Input & Output
6 2
4 4 1 5 3
2 6 2
0
9
3 0 1
5 0 2
1 0 3
3 1 2
2 1 3
3 2 3
4 0 3
5 2 3
6 1 3
11 3
2 4 7
9 9 10 2 3 1 5 8 11 6
0
0
18
7 0 2
6 1 2
11 1 3
8 1 3
5 1 2
1 1 4
3 1 2
2 1 4
3 2 4
4 0 4
5 2 4
6 2 4
7 2 4
8 3 4
10 1 2
9 1 4
10 2 4
11 3 4
Reference
王晓东《计算机算法设计与分析》