5-7 n色方柱问题
问题描述
设有 n 个立方体,每个立方体的每一面用红、黄、蓝、绿等 n 种颜色之一染色。要把这n 个立方体叠成一个方形柱体,使得柱体的 4 个侧面的每一侧均有 n 种不同的颜色。试设计一个回溯算法,计算出 n 个立方体的一种满足要求的叠置方案。
对于给定的 n 个立方体以及每个立方体各面的颜色,计算出 n 个立方体的一种叠置方案,使得柱体的 4 个侧面的每一侧均有 n 种不同的颜色。
数据输入:
第一行有 1 个正整数 n,0< n< 27,表示给定的立方体个 数和颜色数均为 n。第 2 行是 n 个大写英文字母组成的字符串。该字符串的第 k(0≤ k< n) 个字符代表第 k 种颜色。接下来的 n 行中,每行有 6 个数,表示立方体各面的颜色。立方体各面的编号如下图所示。
图中 F 表示前面,B 表示背面,L 表示左面,R 表示右面,T 表示顶面,D 表示底面。相 应地,2 表示前面,3 表示背面,0 表示左面,1 表示右面,5 表示顶面,4 表示底面。
例如,在示例输出文件中,第3行的6个数0 2 1 3 0 0分别表示第1个立方体的左面的颜色为R, 右面的颜色为B, 前面的颜色为G, 背面的颜色为Y, 底面的颜色为R, 顶面的颜色为 R。
Java
package Chapter5HuiSuFa;
import java.util.Scanner;
public class NSeFangZhu {
private static int n,ans;
private static int[][] board,solu;
private static boolean[] used;
private static char[] color;
private static String colors;
public static void main(String[] args){
Scanner input = new Scanner(System.in);
while (true){
n = input.nextInt();
board = new int[n][6];
solu = new int[n][6];
color = new char[n];
used = new boolean[n];
colors = input.next();
color = colors.toCharArray();
for(int i=0; i<n; i++)
for(int j=0; j<6; j++)
board[i][j] = input.nextInt();
search();
if(ans == 0)
System.out.println("No Solution!");
}
}
private static void search(){
int i,t,cube;
boolean newg,over,ok;
int[] vert = new int[n];
int[] edge = new int[n*2];
for(i=0; i<n; i++) vert[i]=0;
t = -1; newg = true;
while (t > -2){
t++;
cube = t%n;//每个立方体找2次
if(newg) edge[t]=-1;
over=false; ok=false;
while (!ok && !over){
edge[t]++;
if(edge[t] > 2) over=true;//每个立方体只有3条边
else ok=(t<n || edge[t]!=edge[cube]);//是否已用过
}
if(!over){
if(++vert[board[cube][edge[t]*2]] > 2+t/n*2) ok=false;
if(++vert[board[cube][edge[t]*2+1]] > 2+t/n*2) ok=false;
if(t%n==n-1 && ok)
for(i=0; i<n; i++)
if(vert[i] > 2+t/n*2) ok=false;
if(ok){
if(t == n*2-1){//找到解
ans++;
out(edge);
return;
}else newg=true;
}else{//取下一条边
--vert[board[cube][edge[t]*2]];
--vert[board[cube][edge[t]*2+1]];
t--; newg=false;
}
}else {//回溯
t--;
if(t > -1){
cube = t%n;
--vert[board[cube][edge[t]*2]];
--vert[board[cube][edge[t]*2+1]];
}
t--; newg=false;
}
}
}
private static void out(int[] edge){
int k,a,b,c,d,i,j;
for(i=0; i<2; i++){
for(j=0; j<n; j++) used[j]=false;
do{
j=0;//找下一条未用边
d=c=-1;
while (j<n && used[j]) j++;
if(j < n)
do{
a = board[j][edge[i*n+j]*2];
b = board[j][edge[i*n+j]*2+1];
if(b == d) {k=a; a=b; b=k;}
solu[j][i*2] = a;
solu[j][i*2+1] = b;
used[j] = true;
if(c < 0) c=a;//开始顶点
d=b;
for(k=0; k<n; k++)//找下一个立方体
if(!used[k] && (board[k][edge[i*n+k]*2]==b || board[k][edge[i*n+k]*2+1]==b))
j = k;
}while (b!=c);
}while (j<n);
}
for(j=0; j<n; j++){
k = 3-edge[j]-edge[j+n];
a = board[j][k*2];
b = board[j][k*2+1];
solu[j][4] = a;
solu[j][5] = b;
}
for(i=0; i<n; i++){
for(j=0; j<6; j++)
System.out.print(color[solu[i][j]]);
System.out.println();
}
}
}
Input & Output
4
RGBY
0 2 1 3 0 0
3 0 2 1 0 1
2 1 0 2 1 3
1 3 3 0 2 2
RBGYRR
YRBGRG
BGRBGY
GYYRBB
10
ABCDEFGHIJ
0 1 7 3 4 0
1 7 3 4 0 1
2 2 2 2 2 2
3 4 0 1 7 3
4 0 1 7 3 4
5 5 5 5 5 5
6 9 8 6 9 8
7 3 4 0 1 7
8 6 9 8 6 9
9 8 6 9 8 6
ABHDEA
BHDEAB
CCCCCC
DEABHD
EABHDE
FFFFFF
GJIGJI
HDEABH
IGJIGJ
JIGJIG
Reference
王晓东《计算机算法设计与分析》(第3版)P181