5-9 拉丁矩阵问题
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int NM=25;
int x[NM][NM],n,m,num,sum;
bool check(int line,int row,int k)
{
int i,j;
for(i=0;i<line;i++){
if(x[i][row]==k) return false;
}
for(j=0;j<row;j++){
if(x[line][j]==k) return false;
}
return true;
}
void Backtarck(int t)
{
int i,j,k;
if(t==num) {
sum++;return;
}
i=t/m;j=t%m; //行;列
for(k=1;k<=n;k++)
{
x[i][j]=k;
if(check(i,j,k))
Backtarck(t+1);
x[i][j]=0;
}
}
int main()
{
while(~scanf("%d%d",&n,&m)) //m<n
{
sum=0;num=n*m;
Backtarck(0);
printf("%d\n",sum);
}
return 0;
}
5-10 排列宝石问题
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int NM=25;
int cor[NM][NM],size[NM][NM],vis[NM][NM];
int num,sum,n;
bool check(int line,int row,int c,int s)
{
int i,j;
for(i=0;i<line;i++){
if(cor[i][row]==c || size[i][row]==s) return false;
}
for(j=0;j<row;j++){
if(cor[line][j]==c || size[line][j]==s) return false;
}
return true;
}
void Backtarck(int t)
{
int i,j,x,y;
if(t==num){
sum++;return;
}
x=t/n;y=t%n;
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
{
if(!vis[i][j]){
cor[x][y]=i;size[x][y]=j;
vis[i][j]=1;
if(check(x,y,i,j))
Backtarck(t+1);
cor[x][y]=0;size[x][y]=0;
vis[i][j]=0;
}
}
}
int main()
{
while(cin>>n)
{
num=n*n;
sum=0;
memset(vis,0,sizeof(vis));
Backtarck(0);
cout<<sum<<endl;
}
return 0;
}
5-11 重复拉丁矩阵问题
理解一:第一行和第一列的宝石排列,不是按最小字典序,但还是最小到最大排列
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int NM=25;
int x[NM][NM],sx[NM][NM],sy[NM][NM],c[NM],v[NM*NM],v1[NM*NM];
int tt[NM],n,m,ans,num,sum;
bool check(int line,int row,int k)
{
int i,j;
if(sx[line][k]>c[k] || sy[row][k]>c[k])
return false;
/*
解法一
if(line==0){
for(j=0;j<row;j++)
if(x[0][j]>k) return false;
}
else if(row==0){
for(i=0;i<line;i++)
if(x[i][0]>k) return false;
}
else {
if(line>0){
for(j=0;j<m-1;j++) //m-1
if(x[0][j]>x[0][j]) return false;
}
if(row>0){
for(i=0;i<line;i++) //line
if(x[i][0]>x[i+1][0]) return false;
}
}
*/
/*解法二*/
if(line==0){
for(i=0;i<row;i++){
if(x[0][i]>k) return false;
}
}
if(row==0){
for(j=0;j<line;j++){
if(x[j][0]>k) return false;
}
}
return true;
}
void Backtarck(int t)
{
int i,j,k;
if(t==num) {
for(i=0;i<num;i++) v1[i]=v[i];
sum++;return;
}
i=t/m;j=t%m; //行;列
for(k=1;k<=ans;k++)
{
x[i][j]=k;sx[i][k]++;sy[j][k]++;
v[t]=k;
if(check(i,j,k))
Backtarck(t+1);
x[i][j]=0;sx[i][k]--;sy[j][k]--;
}
}
int main()
{
int i,j,k;
while(~scanf("%d%d%d",&n,&m,&ans)) //m<n
{
k=0;
for(i=1;i<=ans;i++){
scanf("%d",&c[i]);
for(j=0;j<c[i];j++) tt[k++]=i;
}
sum=0;num=n*m;
for(i=0;i<m;i++) x[0][i]=tt[i];
for(i=0;i<n;i++) x[i][0]=tt[i];
Backtarck(0);
printf("%d\n",sum);
for(i=0;i<num;i++){
cout<<v1[i]<<" ";
if((i+1)%m==0)
cout<<endl;
}
}
return 0;
}
理解二:同书本
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int NM=25;
int x[NM][NM],sx[NM][NM],sy[NM][NM],c[NM],v[NM*NM],v1[NM*NM];
int tt[NM],n,m,ans,num,sum;
bool check(int line,int row,int k)
{
if(sx[line][k]>c[k] || sy[row][k]>c[k])
return false;
return true;
}
void Backtarck(int t)
{
int i,j,k;
if(t==num) {
for(i=0;i<num;i++) v1[i]=v[i];
sum++;return;
}
i=t/m;j=t%m; //行;列
if(x[i][j]) {
v[t]=x[i][j];Backtarck(t+1);
}
else
for(k=1;k<=ans;k++)
{
x[i][j]=k;
sx[i][k]++;sy[j][k]++;
v[t]=k;
if(check(i,j,k)) Backtarck(t+1);
x[i][j]=0;
sx[i][k]--;sy[j][k]--;
}
}
int main()
{
int i,j,k;
while(~scanf("%d%d%d",&n,&m,&ans)) //m<n
{
k=0;
memset(sx,0,sizeof(sx));
memset(sy,0,sizeof(sy));
for(i=1;i<=ans;i++){
scanf("%d",&c[i]);
for(j=0;j<c[i];j++) tt[k++]=i;
}
sum=0;num=n*m;
//先把第一行和第一列的宝石放好
for(i=0;i<m;i++) {
x[0][i]=tt[i];sx[0][tt[i]]=1;sy[i][tt[i]]=1;
}
for(i=0;i<n;i++) {
x[i][0]=tt[i];sy[0][tt[i]]=1;sx[i][tt[i]]=1;
}
Backtarck(0);
printf("%d\n",sum);
for(i=0;i<num;i++){
cout<<v1[i]<<" ";
if((i+1)%m==0)
cout<<endl;
}
}
return 0;
}
/*
4 7 3
2 2 3
1 2 2
1 1
2 3 3
1 1 1
2 4 4
1 1 1 1
*/
本文探讨了多种基于回溯法的拉丁矩阵问题求解算法,包括标准拉丁矩阵、排列宝石问题及重复拉丁矩阵的不同实现方案。通过具体的C++代码示例详细介绍了如何通过检查行和列的约束条件来确保矩阵的正确填充。
4654

被折叠的 条评论
为什么被折叠?



