算法设计与分析: 5-7 n色方柱问题

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 个数,表示立方体各面的颜色。立方体各面的编号如下图所示。
n色方柱问题
图中 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

猜你喜欢

转载自blog.csdn.net/ioio_/article/details/81103520
今日推荐