算法设计与分析: 5-11 重复拉丁矩阵问题

5-11 重复拉丁矩阵问题

问题描述

现有 k 种不同价值的宝石,每种宝石都有足够多颗。欲将这些宝石排列成一个 m 行 n列的矩阵,m≤n,使矩阵中每一行和每一列的同一种宝石数都不超过规定的数量。另外还 规定,宝石阵列的第 1 行从左到右和第 1 列从上到下的宝石按宝石的价值最小字典序从小到 大排列。试设计一个算法,对于给定的 k,m 和 n 以及每种宝石的规定数量,计算出有多少 种不同的宝石排列方案。

对于给定的 m,n 和 k,以及每种宝石的规定数量,计算出不同的宝石排列方案数。

数据输入:
第 1 行有 3 个正整数 m,n 和 k,0< m≤ n< 9。第 2 行有k 个数,第 j 个数表示第 j 种宝石在矩阵的每行和每列出现的最多次数。这 k 个数按照宝石 的价值从小到大排列。设这k个数为 1v1v2...vk 1 ≤ v 1 ≤ v 2 ≤ . . . ≤ v k ,则 v1+v2+...+vk=n v 1 + v 2 + . . . + v k = n

Java

package Chapter5HuiSuFa;

import java.util.Scanner;

public class ChongFuLaDingJuZhen {

    private static int m,n,mm;
    private static int[] mv,mu;
    private static int[][] board;
    private static double count;

    public static void main(String[] args){
        Scanner input = new Scanner(System.in);

        while (true){
            count = 0.0;

            m = input.nextInt();
            n = input.nextInt();
            mm = input.nextInt();

            mv = new int[mm+1];
            mu = new int[n+1];
            board = new int[n+1][n+1];

            for(int k=1,j=1,t=0; k<=mm; k++){
                t = input.nextInt();
                mv[k] = t;
                while (t > 0){
                    mu[j++] = k;
                    t--;
                }
            }
            for(int i=1; i<=n; i++)
                for(int j=1; j<=n; j++)
                    board[i][j] = j;
            for(int i=2; i<=n; i++)
                swap(board[i],1,i);

            backtrack(2,2);

            System.out.println((int)count);
        }
    }

    private static void swap(int[] x, int i, int j){
        int tmp = x[i];
        x[i] = x[j];
        x[j] = tmp;
    }

    private static void backtrack(int r, int c){
        for(int i=c; i<=n; i++)
            if(ok(r,c,i)){
                swap(board[r],c,i);
                if(c == n){
                    if(r == m) count += 1.0;
                    else backtrack(r+1,2);
                }else backtrack(r,c+1);
                swap(board[r],c,i);
            }
    }

    private static boolean ok(int r, int c, int s){
        int i,j;
        int k = board[r][s];
        if(s > c)
            for(int t=c; t<s; t++)
                if(mu[board[r][t]] == mu[k])
                    return false;
        for(i=1,j=0; i<r; i++)
            if(mu[board[i][c]] == mu[k])
                j++;
        if(j > mv[mu[k]]-1)
            return false;
        else return true;
    }
}

Input & Output

4 7 3
2 2 3
84309

5 7 3
1 2 4
285216

Reference

王晓东《计算机算法设计与分析》(第3版)P183

    原文作者:拉丁方阵问题
    原文地址: https://blog.csdn.net/IOIO_/article/details/81107971
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞