用Visual C++6.0实现棋盘覆盖分治算法

本文介绍了一种使用L型骨牌覆盖特殊棋盘的算法实现,通过递归方法完成覆盖过程,并利用MFC实现了可视化界面,允许用户设置特殊方格位置及棋盘级别。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、问题描述
       在一个2k×2k个方格组成的棋盘中,恰有一个方格与其它方格不同,称该方格为一特殊方格,且称该棋盘为一特殊棋盘。在棋盘覆盖问题中,要用4种不同形态的L型骨牌覆盖给定的特殊棋盘上除特殊方格以外的所有方格,且任何2个L型骨牌不得重叠覆盖。
       当k>0时,将2k×2k棋盘分割为4个2k-1×2k-1子棋盘,特殊方格必位于4个较小子棋盘之一中,其余3个子棋盘中无特殊方格。为了将这3个无特殊方格的子棋盘转化为特殊棋盘,可以用一个L型骨牌覆盖这3个较小棋盘的会合处,从而将原问题转化为4个较小规模的棋盘覆盖问题。递归地使用这种分割,直至棋盘简化为棋盘1×1。

二、程序
        (1)新建一个基于对话框的工程Ex0420Chess。

        (2)打开类视图,为CEx0420ChessDlg类添加以下成员变量和函数:

None.gifint tile;     //当前方块
None.gif
int **board; //指向棋盘的指针
None.gif
int m_dw; //棋盘每一格的宽度
None.gif
void chessBoard(int tr,int tc, int dr, int dc,int size); //棋盘覆盖算法
None.gif
void DrawSubBoard(int x,int y,int w,int c); //画棋盘的x行,y列的方块,w表示宽度,c表示颜色值
None.gif

None.gif

       (3)在对话框上增加三个编辑框,ID分别为IDC_K、IDC_DR和IDC_DC,并为它们分别关联一个int型的变量m_k、m_dr和m_dc。然后添加三个按钮,ID分别为IDC_DRAW、IDC_DRAWBOAR和DIDC_CLEAR,标题分别为画棋盘、覆盖和清空。        (4)本实验棋盘的大小固定为256×256,k值越大,方格越多,这时每个方格的尺寸越小。为给每个L型骨牌填充不同的颜色,程序中将tile的值转换成颜色值,画一个方格的函数DrawSubBoard()的定义如下:
None.gifvoid CEx0420ChessDlg::DrawSubBoard(int x, int y, int w, int c)
ExpandedBlockStart.gifContractedBlock.gif
dot.gif{
InBlock.gif    CClientDC dc(
this);
InBlock.gif    COLORREF clr;
InBlock.gif    clr 
= RGB(c*c/256,c*c*c/256,c*c*c*c/256);     //将c值转换成颜色值
InBlock.gif
    CBrush br(clr);
InBlock.gif    CRect r;
InBlock.gif    r.top 
= 10 + x*m_dw;
InBlock.gif    r.bottom 
= r.top + m_dw;
InBlock.gif    r.left 
= 10+ y*m_dw;
InBlock.gif    r.right 
= r.left + m_dw;
InBlock.gif    dc.FillRect(
&r,&br);
ExpandedBlockEnd.gif}

None.gif

 使用分治算法覆盖棋盘,为清楚看到覆盖棋盘的顺序,每次覆盖完一个L型骨牌后停顿0.5秒,chessBoard()函数源程序如下:

None.gifvoid CEx0420ChessDlg::chessBoard(int tr, int tc, int dr, int dc, int size)
ExpandedBlockStart.gifContractedBlock.gif
dot.gif{
InBlock.gif    
if(1 == size)
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        
return;
ExpandedSubBlockEnd.gif    }

InBlock.gif    Sleep(
500);                             //覆盖L型骨牌后停顿0.5秒,以便观察
InBlock.gif
    int t = this->tile++;
InBlock.gif    
int s = size/2;
InBlock.gif    
if(dr < tr+&& dc < tc+s)
InBlock.gif        chessBoard(tr,tc,dr,dc,s);
InBlock.gif    
else
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        board[tr
+s-1][tc+s-1= t;
InBlock.gif        chessBoard(tr,tc,tr
+s-1,tc+s-1,s);
InBlock.gif        
this->DrawSubBoard(tr+s-1,tc+s-1,m_dw,t);//递归过程中,此子棋盘中没有特殊方格,调用DrawSubBoard()函数画一个方格,并填充颜色
ExpandedSubBlockEnd.gif
    }

InBlock.gif    
if(dr < tr+&& dc >= tc+s)
InBlock.gif        chessBoard(tr,tc
+s,dr,dc,s);
InBlock.gif    
else
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        board[tr
+s-1][tc+s] = t;
InBlock.gif        chessBoard(tr,tc
+s,tr+s-1,tc+s,s);
InBlock.gif        
this->DrawSubBoard(tr+s-1,tc+s,m_dw,t);
ExpandedSubBlockEnd.gif    }

InBlock.gif
InBlock.gif    
if(dr >= tr+&& dc < tc+s)
InBlock.gif        chessBoard(tr
+s,tc,dr,dc,s);
InBlock.gif    
else
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        board[tr
+s][tc+s-1= t;
InBlock.gif        chessBoard(tr
+s,tc,tr+s,tc+s-1,s);
InBlock.gif        
this->DrawSubBoard(tr+s,tc+s-1,m_dw,t);
ExpandedSubBlockEnd.gif    }

InBlock.gif
InBlock.gif    
if(dr >= tr+&& dc >= tc+s)
InBlock.gif        chessBoard(tr
+s,tc+s,dr,dc,s);
InBlock.gif    
else
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        board[tr
+s][tc+s] = t;
InBlock.gif        chessBoard(tr
+s,tc+s,tr+s,tc+s,s);
InBlock.gif        
this->DrawSubBoard(tr+s,tc+s,m_dw,t);
ExpandedSubBlockEnd.gif    }

ExpandedBlockEnd.gif}

None.gif
 

    (5)为三个按钮分别添加消息响应函数

None.gif//点击"画棋盘"按钮消息响应函数
None.gif
void CEx0420ChessDlg::OnDraw() 
ExpandedBlockStart.gifContractedBlock.gif
dot.gif{
InBlock.gif    UpdateData();                        
//更新编辑框中数据,重要
InBlock.gif
    if(m_k > 5)
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        
this->MessageBox("为了方便演示,建议输入1-5的整数!");
ExpandedSubBlockEnd.gif    }

InBlock.gif    
else
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        
this->OnClear();                //当输入一个新的k值时,清空原有图形
InBlock.gif
        CClientDC dc(this);
InBlock.gif        
int k = this->m_k;
InBlock.gif        
this->m_dw = 256/(int)pow(2,k); //棋盘区域大小固定为256*256,根据k值计算方格宽度
InBlock.gif
        for(int i = 10;i<=267;i+=m_dw)  //画棋盘
ExpandedSubBlockStart.gifContractedSubBlock.gif
        dot.gif{
InBlock.gif            dc.MoveTo(
10,i);
InBlock.gif            dc.LineTo(
267,i);
InBlock.gif            dc.MoveTo(i,
10);
InBlock.gif            dc.LineTo(i,
267);
ExpandedSubBlockEnd.gif        }

ExpandedSubBlockEnd.gif    }

ExpandedBlockEnd.gif}

None.gif
//点击"覆盖"按钮消息响应函数
None.gif
void CEx0420ChessDlg::OnDrawboard() 
ExpandedBlockStart.gifContractedBlock.gif
dot.gif{
InBlock.gif    UpdateData();
InBlock.gif    
if(m_dr >= (int)pow(2,m_k) || m_dc >= (int)pow(2,m_k) || m_dr < 0 || m_dc < 0)
InBlock.gif          
//判断dr,dc中数据是否溢出
ExpandedSubBlockStart.gifContractedSubBlock.gif
    dot.gif{
InBlock.gif        
this->MessageBox("特殊方格行号或列号错误,请重新输入!");
ExpandedSubBlockEnd.gif    }

InBlock.gif    
else
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        
//调用以下两个函数重新进行覆盖
InBlock.gif
        this->OnClear();
InBlock.gif        
this->OnDraw();
InBlock.gif        
//得到特殊方格的行号和列号后,将它用黑色填充,以作标记
InBlock.gif
        CClientDC dc(this);
InBlock.gif        COLORREF clr;
InBlock.gif        clr 
= RGB(0,0,0);
InBlock.gif        CBrush br(clr);
InBlock.gif        CRect r;
InBlock.gif        
int w = 256/(int)pow(2,m_k);
InBlock.gif        r.top 
= 10 + m_dr*w;
InBlock.gif        r.bottom 
= r.top + w;
InBlock.gif        r.left 
= 10 + m_dc*w;
InBlock.gif        r.right 
= r.left + w;
InBlock.gif        dc.FillRect(
&r,&br);
InBlock.gif        Sleep(
1000);
InBlock.gif        
this->chessBoard(0,0,this->m_dr,this->m_dc,(int)pow(2,this->m_k));
ExpandedSubBlockEnd.gif    }

ExpandedBlockEnd.gif}

None.gif
//点击“清空”按钮清空棋盘区域原有图形
None.gif
void CEx0420ChessDlg::OnClear() 
ExpandedBlockStart.gifContractedBlock.gif
dot.gif{
InBlock.gif    CClientDC dc(
this);
InBlock.gif    dc.Rectangle(
10,10,267,267);
InBlock.gif    
ExpandedBlockEnd.gif}

None.gif

三、注意
    本程序定义了一个指向指针的指针**board,在使用时必须进行初始化,初始化的方法为:

None.gifboard = new int*[50];                  
None.gif
for(int i = 0;i<50;i++)
None.gif    board[i] 
= new int[50];

转载于:https://www.cnblogs.com/ioleon13/archive/2007/05/02/734713.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值