智力拼图问题

#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;
}

这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值