智力拼图算法
题目
全局变量
int brow, bcol; //brow * bcol 的矩形
dom orig[12]; //12个图形 //dom类是由五个小方块组成得图形
dom var[12][8]; //存储12个图形中的每个图形的不同形态
int nvar[12]; //存储12个图形的不同形态数(就是一个图形有几个变换形态)
///dom类
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];
}
};
init();
//得到所有图形的所有形态,存储于var[][]中,形态数存在于nvar[]中
void init()
{
originit(); //将每个图形结构按其编号存储于数组orig中
for(int i=0; i < 12; i++) //循环12次
{
dom dom1(orig[i].aa); //dom.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)) /判断两种图形是否相同 domeq(dom dom1, dom dom2)
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; //记录不同形态数
}
}
//将每个图形结构按其编号存储于数组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);
}
//判断两种图形是否相同
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;
}
//旋转 //不是以中心点旋转,每次都靠近左上角 逆时针旋转90°
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]; //复制src得数据
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++;
}
}
初始化完了后,所有准备操作都完成
Fboard类
//表示给定矩形的形态
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(int i=0; i<60; i++)
{
pos[i] = x.pos[i];
}
}
void copy(Fboard x)
{
//int i = 0;
for(int i=0; i<12; i++)
mark[i] = x.mark[i];
for(int i=0; i<60; i++)
pos[i] = x.pos[i];
}
};
search()函数
int ans = 0; //全局变量ans
void search(Fboard pre)
{
int npla = 0, frow = 0, fcol = 0;
//Fboard ff = Fboard(pre);
Fboard ff(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(int 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);
}
}
}
}
}
源码
#include <iostream>
#include <fstream>
#include <cstring>
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(int i=0; i<60; i++)
{
pos[i] = x.pos[i];
}
}
void copy(Fboard x)
{
//int i = 0;
for(int i=0; i<12; i++)
mark[i] = x.mark[i];
for(int i=0; i<60; i++)
pos[i] = x.pos[i];
}
};
//判断两种图形是否相同
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]; //复制src得数据
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++) //循环12次
{
dom dom1(orig[i].aa); //dom.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)) /判断两种图形是否相同 domeq(dom dom1, dom dom2)
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; //记录不同形态数
}
}
//将二维数组标记转换为一维数组
int addr(int row, int col)
{
return (row - 1) * bcol + col - 1;
}
//检测图形覆盖的可行性
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 out_number = 0;
int ans = 0;
void search(Fboard pre)
{
int npla = 0;//计录已用过的图形数
int frow = 0;
int fcol = 0;
//Fboard ff = Fboard(pre);
Fboard ff(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(int 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);
cout << endl << ++out_number << endl;
return;
//npla = 0;
}
else
search(ff);
//回溯
ff.copy(pre);
}
}
}
}
}
int main()
{
// ifstream fin("智力拼图.txt");
// cout << "输入矩阵行数,列数:";
// fin >> brow >> bcol;
// cout << brow << " " << bcol << endl;
brow = 6;
bcol = 10;
cout << "拼图如下:\n";
if(bcol<3 || brow*bcol!=60)
cout << "No Solutiobcol!\n";
else
{
init();
Fboard ff;
search(ff);
}
cout << endl;
//fin.close();
return 0;
}