#include <iostream>
#include <fstream>
using namespace std;
int brow, bcol; //brow * bcol 的矩形
class dom
{
public:
int aa[5][5]; //存储给定的每个图形
dom()
{
for(int i=0; i<5; i++)
for(int j=0; j<5; j++)
aa[i][j] = 0;
}
dom(int bb[5][5])
{
for(int i=0; i<5; i++)
for(int j=0; j<5; j++)
aa[i][j] = bb[i][j];
}
};
dom orig[12]; //12个图形
dom var[12][8]; //存储12个图形中的每个图形的不同形态
int nvar[12]; //存储12个图形的不同形态数
//将每个图形结构按其编号存储于数组orig中
void originit()
{
int pc[5][5];
memset(pc, 0, sizeof(pc));
pc[0][0] = 1; pc[0][1] = 1; pc[0][2] = 1;
pc[1][0] = 1;
pc[2][0] = 1;
orig[0] = dom(pc);
memset(pc, 0, sizeof(pc));
pc[0][0] = 2; pc[0][1] = 2;
pc[1][0] = 2;
pc[2][0] = 2; pc[2][1] = 2;
orig[1] = dom(pc);
memset(pc, 0, sizeof(pc));
pc[0][0] = 3; pc[0][1] = 3;
pc[1][0] = 3; pc[1][1] = 3;
pc[2][0] = 3;
orig[2] = dom(pc);
memset(pc, 0, sizeof(pc));
pc[0][0] = 4; pc[0][1] = 4;
pc[1][0] = 4;
pc[2][0] = 4;
pc[3][0] = 4;
orig[3] = dom(pc);
memset(pc, 0, sizeof(pc));
pc[0][1] = 5; pc[0][2] = 5; pc[0][3] = 5;
pc[1][0] = 5; pc[1][1] = 5;
orig[4] = dom(pc);
memset(pc, 0, sizeof(pc));
pc[0][0] = 6;
pc[1][0] = 6;
pc[2][0] = 6; pc[2][1] = 6;
pc[3][0] = 6;
orig[5] = dom(pc);
memset(pc, 0, sizeof(pc));
pc[0][0] = 7;
pc[1][0] = 7; pc[1][1] = 7; pc[1][2] = 7;
pc[2][0] = 7;
orig[6] = dom(pc);
memset(pc, 0, sizeof(pc));
pc[0][1] = 8;
pc[1][0] = 8; pc[1][1] = 8; pc[1][2] = 8;
pc[2][1] = 8;
orig[7] = dom(pc);
memset(pc, 0, sizeof(pc));
pc[0][0] = 9; pc[0][1] = 9;
pc[1][1] = 9; pc[1][2] = 9;
pc[2][1] = 9;
orig[8] = dom(pc);
memset(pc, 0, sizeof(pc));
pc[0][0] = 10; pc[0][1] = 10; pc[0][2] = 10; pc[0][3] = 10; pc[0][4] = 10;
orig[9] = dom(pc);
memset(pc, 0, sizeof(pc));
pc[0][0] = 11; pc[0][1] = 11;
pc[1][1] = 11; pc[1][2] = 11;
pc[2][2] = 11;
orig[10] = dom(pc);
memset(pc, 0, sizeof(pc));
pc[0][0] = 12; pc[0][1] = 12;
pc[1][1] = 12;
pc[2][1] = 12; pc[2][2] = 12;
orig[11] = dom(pc);
}
//表示给定矩形的形态
class fboard
{
public:
int pos[60]; //表示矩形中60个方格被覆盖的情况
int mark[12]; //用于标记使用过的图形
fboard()
{
memset(pos, 0, sizeof(pos));
memset(mark, 0, sizeof(mark));
}
fboard(fboard &x)
{
for(int i=0; i<12; i++)
mark[i] = x.mark[i];
for(i=0; i<60; i++)
pos[i] = x.pos[i];
}
void copy(fboard x)
{
for(int i=0; i<12; i++)
mark[i] = x.mark[i];
for(i=0; i<60; i++)
pos[i] = x.pos[i];
}
};
int addr(int row, int col)
{
return (row-1) * bcol + col - 1;
}
//判断两种图形是否相同
bool domeq(dom dom1, dom dom2)
{
for(int i=0; i<5; i++)
for(int j=0; j<5; j++)
if(dom1.aa[i][j] != dom2.aa[i][j])
return false;
return true;
}
//旋转
void rotp(dom &des, dom &src)
{
memset(des.aa, 0, sizeof(des.aa));
for(int x=4, flag=0, xp=0; x>=0; x--)
{
for(int y =0; y<5; y++)
{
des.aa[xp][y] = src.aa[y][x];
if(src.aa[y][x]>0)
flag = 1;
}
if(flag >0)
xp++;
}
}
//翻转
void flip(dom &des, dom &src)
{
memset(des.aa, 0, sizeof(des.aa));
for(int x=4, flag=0, xp=0; x>=0; x--)
{
for(int y=0; y<5; y++)
{
des.aa[y][xp] = src.aa[y][x];
if(src.aa[y][x]>0)
flag = 1;
}
if(flag > 0)
xp++;
}
}
//得到所有图形的所有形态,存储于var[][]中,形态数存在于nvar[]中
void init()
{
originit(); //将每个图形结构按其编号存储于数组orig中
for(int i=0; i<12; i++)
{
dom dom1(orig[i].aa);
int vc = 0; //该种图形的不同形态数
for(int j=0; j<8; j++) //翻转,旋转,最多8种形态
{
bool exist = false;
for(int k=0; k<vc && !exist; k++) //该图形的形态是否出现过
if(domeq(var[i][k], dom1))
exist = true;
if(!exist) //没有出现过
var[i][vc++] = dom(dom1.aa); //记录
dom dom2 = dom(dom1.aa);
rotp(dom1, dom2); //旋转
if(j == 3)
{
dom2 = dom(dom1.aa);
flip(dom1, dom2); //翻转
}
}
nvar[i] = vc; //记录不同形态数
}
}
//检测图形覆盖的可行性
bool check(dom tryp, fboard ff, int px, int py)
{
for(int row=0; row<5; row++)
for(int col=0; col<5; col++)
if(tryp.aa[row][col]>0)
{
int r = row + py;
int c = col + px;
if(r>brow || c>bcol || ff.pos[addr(r, c)]>0)
return false;
}
return true;
}
//输出图形
void outf(fboard ff)
{
for(int row=1; row<=brow; row++)
{
for(int col=1; col<=bcol; col++)
{
int x = ff.pos[addr(row, col)];
if(x<10)
cout << x;
if(x==10)
cout << 'a';
if(x==11)
cout << 'b';
if(x==12)
cout << 'c';
}
cout << endl;
}
}
int ans = 0;
void search(fboard pre)
{
int npla = 0, frow = 0, fcol = 0;
fboard ff = fboard(pre);
if(ans > 0)
return;
//找最左上的未覆盖方格
for(int row = 1, found = 0; row <= brow && found==0; row++)
for(int col=1; col <=bcol && found == 0; col++)
if(pre.pos[addr(row, col)] == 0)
{
frow = row;
fcol = col;
found = 1;
}
//计算已用过的图形数
for(int pn=0; pn<12; pn++)
if(pre.mark[pn]>0)
npla++;
for(pn=0; pn<12; pn++)
{
if(pre.mark[pn]>0) //已经用过
continue;
//对每种不同的形态
for(int pv=0; pv<nvar[pn]; pv++)
{
dom tryp = var[pn][pv];
int py = frow;
for(int px=1; px<bcol; px++)
{
if(px > fcol)
break;
if(check(tryp, ff, px, py))
{
//用该图形覆盖
for(int row=0; row<5; row++)
for(int col=0; col<5; col++)
if(tryp.aa[row][col]>0)
ff.pos[addr(row+py, col+px)] = tryp.aa[row][col];
ff.mark[pn] = 1;
if(npla > 10) //12种图形都试过
{
++ans;
outf(ff);
return;
}
else
search(ff);
//回溯
ff.copy(pre);
}
}
}
}
}
int main()
{
ifstream fin("智力拼图.txt");
cout << "输入矩阵行数,列数:";
fin >> brow >> bcol;
cout << brow << " " << bcol << endl;
cout << "拼图如下:\n";
if(bcol<3 || brow*bcol!=60)
cout << "No Solutiobcol!\n";
else
{
init();
fboard ff;
search(ff);
}
cout << endl;
fin.close();
return 0;
}
智力拼图问题
最新推荐文章于 2024-04-01 13:00:00 发布