一.问题描述
二.如何证明可解-数学归纳法
·当n=1(2x2棋盘),易得问题有解;
·则假设当n=k(x棋盘),该问题有解。那么此时当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为特殊方格位置):
四.算法分析
五.结语
本篇文章中图片来自本校课程课件,代码为作者对问题的尝试解决方案。如有错误,欢迎各位大佬指正。
如有侵权请联系删除,转载需标明出处。