[东北大学算法设计与分析] 棋盘覆盖问题的C++实现

 一.问题描述

二.如何证明可解-数学归纳法

        ·当n=1(2x2棋盘),易得问题有解;

        ·则假设当n=k(2^{k}x2^{k}棋盘),该问题有解。那么此时当n=k+1,棋盘可划分为四个尺寸为n=k的子棋盘。特殊方格位于三个子棋盘之一,而其余三个子棋盘无特殊方格。

        ·子棋盘的转化:可将一个L型骨牌覆盖在三个子棋盘的汇合处(如下图),此时原问题即可转化为4个n=k棋盘的子问题。又因为n=k时问题有解,所以n=k+1时问题仍有解。

                                        

                                                        骨牌覆盖方式如上

三.C++实现-分治法

        求解思路如下:

        代码实现:

#include <iostream>
#include <vector>


using namespace std;

vector<vector<int>> chessboard;

//存储特殊行列的位置
int special_row = 0;
int special_column = 0;

//L型骨牌编号
int tile = 0;

int init_size()//棋盘初始化
{
    int size;
    cout << "输入棋盘的行列数:"; 
    cin >> size;
    cin.get();
    if((size % 2 != 0 && size != 1) || size == 0){
        cout << "输入的尺寸错误,请重新输入" << endl;
        return init_size();
    }
    else{
        return size;
    }
    return -1;
}

void load_special_chess(int size)//加载特殊方格位置
{
    int position;
    cout << "输入特殊棋子的位置:" << endl;
    cout << "行(1~" << size << "):";
    cin >> position;
    cin.get();
    if(position > size || position < 1){
        cout << "输入的行数错误,请重新输入" << endl;
        system("pause");
        system("cls");
        return load_special_chess(size);
    }
    else{
        special_row = position-1;
        cout << "列(1~" << size << "):";
        cin >> position;
        cin.get();
        if(position > size || position < 1){
            cout << "输入的列数错误,请重新输入" << endl;
            system("pause");
            system("cls");
            load_special_chess(size);
        }
        else{
            special_column = position-1;
            chessboard[special_row][special_column] = -1;
            return;
        }
    }
}

void show_chessboard(int state)//打印棋盘
{
    if(state == 0){
        cout << "初始棋盘:"<<endl;
    }
    else{
        cout << "算法执行后棋盘:"<<endl;
    }
    for(int i = 0;i < chessboard.size();i++){
        for(int j = 0;j < chessboard[i].size();j++){
            cout << chessboard[i][j] << "\t";
        }
        cout << endl;
    }
}

void overlay_Chessboard(int tr,int tc,int dr,int dc,int size)
{   
    if (size == 1){
        return;
    }
    int t = tile++;//L型骨牌号
    int s = size / 2;

    //覆盖左上角棋盘
    if(dr < tr + s && dc < tc + s){//有特殊方格则划分
        overlay_Chessboard(tr,tc,dr,dc,s);
    }
    else{//无特殊方格则先覆盖后划分
        chessboard[tr + s - 1][tc + s - 1] = t;//t号L型骨牌覆盖右下角
        overlay_Chessboard(tr,tc,tr + s - 1,tc + s - 1,s);
    }

    //覆盖右上角棋盘
    if(dr < tr + s && dc >= tc + s){//有特殊方格则划分
        overlay_Chessboard(tr,tc + s,dr,dc,s);
    }
    else{//无特殊方格则先覆盖后划分
        chessboard[tr + s - 1][tc + s] = t;//t号L型骨牌覆盖左下角
        overlay_Chessboard(tr,tc + s,tr + s - 1,tc + s,s);
    }

    //覆盖左下角棋盘
    if(dr >= tr + s && dc < tc + s){//有特殊方格则划分
        overlay_Chessboard(tr + s,tc,dr,dc,s);
    }
    else{//无特殊方格则先覆盖后划分
        chessboard[tr + s][tc + s - 1] = t;//t号L型骨牌覆盖右上角
        overlay_Chessboard(tr + s,tc,tr + s,tc + s - 1,s);
    }

    //覆盖右下角棋盘
    if(dr >= tr + s && dc >= tc + s){//有特殊方格则划分
        overlay_Chessboard(tr + s,tc + s,dr,dc,s);
    }
    else{//无特殊方格则先覆盖后划分
        chessboard[tr + s][tc + s] = t;//t号L型骨牌覆盖左上角
        overlay_Chessboard(tr + s,tc + s,tr + s,tc + s,s);//覆盖右上角子棋盘
    }
}


int main()
{
    int initial_Size;
    
    initial_Size = init_size();//初始化棋盘尺寸

    if(initial_Size != 0){
        chessboard.resize(initial_Size,vector<int>(initial_Size,0));//初始化棋盘
    }
    else{
        cout << "ERROR" << endl;
        system("pause");
        return 0;
    }

    load_special_chess(initial_Size);
    show_chessboard(0);//展示原始棋盘
    overlay_Chessboard(0,0,special_row,special_column,initial_Size);//核心功能
    show_chessboard(1);//展示处理后棋盘

    system("pause");
    return 0;
}

        运行结果(-1为特殊方格位置):

四.算法分析

五.结语

        本篇文章中图片来自本校课程课件,代码为作者对问题的尝试解决方案。如有错误,欢迎各位大佬指正。

        如有侵权请联系删除,转载需标明出处。

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值