智力拼图算法

智力拼图算法

题目

请添加图片描述

全局变量

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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值