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
*/