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

本文探讨了如何设计算法解决重复拉丁矩阵问题,其中宝石被排列成m行n列的矩阵,每行每列同种宝石不超过规定数量。问题要求第1行和第1列按宝石价值从小到大排列。给定m,n,k和每种宝石的最大出现次数,求解不同排列方案的数量。数据输入包括m,n,k以及每种宝石的限制次数。

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...vk1≤v1≤v2≤...≤vk,则v1+v2+...+vk=nv1+v2+...+vk=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

评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值