拉丁矩阵问题

来源:互联网 发布:天启软件华为 编辑:程序博客网 时间:2024/04/28 19:37
问题描述:
现有N种不同形状的宝石,每种宝石有足够多颗。欲将这些宝石排列成m行n列的一个矩阵,m<=n,使矩阵中每一行和每一列的宝石都没有相同形状。试设计一个算法,计算出对于给定的m和n,有多少种不同的宝石排列方案。
算法设计:
对于给定的m和n,计算出不同的宝石排列方案数。
数据输入:
第一行有2个正整数m和n,0<9。
结果输出:
将计算出的宝石排列方案数输出。

分析:
标准拉丁矩阵:宝石矩阵的第一行从左到右排列为1,2,3.....n,且第一列从上到下排列为1,2,3....m的阵列。
设m行n列的标准拉丁矩阵个数为L(m,n)。一般情况下,m行n列的拉丁矩阵个数为R(m,n).本题要求R(m,n)。

公式:R(m,n)=n!(n-1)!L(m,n)/(n-m)!

具体代码:

#include<stdio.h>#include<stdlib.h>int num[10][10];int m,n;int count=0;void swap(int *num1,int *num2){    int temp;    temp = *num1;    *num1 = *num2;    *num2 = temp;}int yes(int r,int c,int k){    int i;    for(i = 1; i < r; i++)        if(num[i][c] == k) return 0;        return 1;}void backtrack(int r,int c){    int i, j;    for(i = c; i <= n;i++){        if(yes(r,c,num[r][i])){            swap(&num[r][c],&num[r][i]);            if(c == n){            if(r == m){                count+=1;            }else {backtrack(r+1,2);}        }else {backtrack(r,c+1);}            swap(&num[r][c],&num[r][i]);        }    }}int main(){    int i, j, temp;    scanf("%d %d",&m,&n);    for(i = 1; i <= n; ++i)    for(j = 1; j<=n; ++j)        num[i][j] = j;    for(i = 2; i <= n; ++i)        swap(&num[i][1],&num[i][i]);        if(m == n) m --;        backtrack(2,2);        int sum = 1;        int sum1 = 1;        for(int i = 1; i <= n; i++)            sum *= i;        for(int i = 1; i <= n-1; i++)            sum *= i;        for(int i = 1;i <= n - m; i++)            sum1 *= i;        printf("%d\n",(sum*count)/sum1);        return 0;}


原创粉丝点击