棋盘覆盖问题
问题描述:一个正方形棋盘的边长为2^k。在所有棋盘中有一个障碍棋格,请用L型骨牌填充满整个棋盘,其中障碍棋格不能放置骨牌。
解题思路:使用分治法的思路,棋盘覆盖问题,通过在棋盘的中心位置放置一个L形骨牌,将原问题拆分成四个相同规模的子问题,再对各个子问题递归求解。递归函数的出口为在2*2的棋盘中放置一个L形骨牌。
第一个骨牌为如下放置方法。可以看出原问题被划分为了四个子问题,每个子棋格都存在一个不能放置的棋格。
接下来再看一下只关注其中一个子问题的解决方法。可以清楚的看到程序在解决问题的过程中一直递归的关注左上角的子问题,最终以解决子问题作为递归出口。
接下里我们运行一下程序,看一下最终结果。这里我稍微换了一下颜色,障碍棋格用白色表示。
代码:
我拿QT+c++写的,QT这方面没有做太多注释。
Graph类:
头文件:
#ifndef GRAPH_H
#define GRAPH_H
class Graph
{
public:
int rowCount;
int columnCount;
int **graph;
Graph(int row, int column);
};
#endif // GRAPH_H
源文件:
#include "graph.h"
#include <stdlib.h>
Graph::Graph(int row, int column)
{
rowCount = row;
columnCount = column;
graph = (int**)malloc(sizeof(int*) * rowCount);
for (int i = 0; i < rowCount; i++)
{
graph[i] = (int*)malloc(sizeof(int) * columnCount);
for (int j = 0; j < columnCount; j++)
{
graph[i][j] = 0;
}
}
}
Window类:
头文件:
#ifndef WINDOW_H
#define WINDOW_H
#include <QWidget>
#include <QLabel>
#include <QPicture>
#include <QPainter>
#include <QGridLayout>
//#include <QVBoxLayout>
class Window : public QWidget
{
Q_OBJECT
public:
Window(int** graph, QWidget *parent = nullptr);//根据graph中存放的数据绘制棋盘
~Window();
private:
QLabel *label[16][16];
signals:
public slots:
};
#endif // WINDOW_H
源文件:
#include "window.h"
Window::Window(int** graph, QWidget *parent) : QWidget(parent)
{
QPicture pic[8];
QPainter painter;
//颜色1
painter.begin(&pic[0]);
painter.setBrush(QBrush(QColor(100,100,0)));
painter.drawRect(0,0,30,30);
painter.end();
//颜色2
painter.begin(&pic[1]);
painter.setBrush(QBrush(QColor(0,255,0)));
painter.drawRect(0,0,30,30);
painter.end();
//颜色3
painter.begin(&pic[2]);
painter.setBrush(QBrush(QColor(0,0,255)));
painter.drawRect(0,0,30,30);
painter.end();
//颜色4
painter.begin(&pic[3]);
painter.setBrush(QBrush(QColor(50,100,20)));
painter.drawRect(0,0,30,30);
painter.end();
//颜色5
painter.begin(&pic[4]);
painter.setBrush(QBrush(QColor(255,0,0)));
painter.drawRect(0,0,30,30);
painter.end();
//颜色6
painter.begin(&pic[5]);
painter.setBrush(QBrush(QColor(255,255,0)));
painter.drawRect(0,0,30,30);
painter.end();
//颜色7
painter.begin(&pic[6]);
painter.setBrush(QBrush(QColor(0,255,255)));
painter.drawRect(0,0,30,30);
painter.end();
//白色(障碍棋格)
painter.begin(&pic[7]);
painter.setBrush(QBrush(QColor(255,255,255)));
painter.drawRect(0,0,30,30);
painter.end();
QGridLayout *gridlayout = new QGridLayout();
gridlayout->setMargin(0);
gridlayout->setSpacing(0);
this->setLayout(gridlayout);
for (int i = 0; i < 16; i++)
{
for (int j = 0; j < 16; j++)
{
label[i][j] = new QLabel(this);
if (graph[i][j] == 1)
label[i][j]->setPicture(pic[7]);
else
label[i][j]->setPicture(pic[graph[i][j] % 7]);
label[i][j]->setScaledContents(true);
label[i][j]->setMaximumSize(30,30);
}
}
for (int i = 0; i < 16; i++)
{
for (int j = 0; j < 16; j++)
{
gridlayout->addWidget(label[i][j], i ,j);
}
}
}
Window::~Window()
{
}
主函数:
#include "window.h"
#include <QApplication>
#include "graph.h"
#include <cstdlib>
#include <ctime>
//递归函数(fun)声明
//graph:存放整个棋盘信息的二维数组 rowBegin:关注问题的起始行坐标 columnBegin:关注问题的列坐标 edge:关注问题的棋盘边长 countp:计数器指针
void fun(int ** graph, int rowBegin, int columnBegin, int edge, int *countp);
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Graph *graph = new Graph(16,16);//创建16*16的棋盘
srand((int)time(0));
graph->graph[rand() % 16][rand() % 16] = 1;//在16*16的棋盘中随机选择一个棋格不能放置骨牌
int count = 1;//计数器:计数所放置的骨牌数
int *countp = &count;//计数器指针
fun(graph->graph,0,0,16,countp);//传入递归函数
Window *w = new Window(graph->graph);
w->show();
return a.exec();
}
void fun(int ** graph, int rowBegin, int columnBegin, int edge, int *countp)
{
if (edge == 2)//递归出口
{
for (int i = 0; i < 2; i++)
{
for (int j = 0; j < 2; j++)
{
if (graph[rowBegin + i][columnBegin + j] == 0)
graph[rowBegin + i][columnBegin + j] = *countp + 1;
}
}
(*countp)++;//计数器+1
}
else
{
int rowIndex = -1;
int columnIndex = -1;
//寻找不能放置骨牌的棋格,其坐标存入rowIndex与columnIndex中
for (int i = 0; i < edge; i++)
{
for (int j = 0; j < edge; j++)
{
if (graph[rowBegin + i][columnBegin + j] != 0)
{
rowIndex = i;
columnIndex = j;
}
}
}
//在棋盘中心给出放置一个L形骨牌
if (rowIndex >= edge / 2)
{
graph[rowBegin + edge / 2 - 1][columnBegin + edge / 2 - 1] = *countp + 1;
graph[rowBegin + edge / 2 - 1][columnBegin + edge / 2] = *countp + 1;
}
else
{
graph[rowBegin + edge / 2][columnBegin + edge / 2 - 1] = *countp + 1;
graph[rowBegin + edge / 2][columnBegin + edge / 2] = *countp + 1;
}
if (columnIndex >= edge / 2)
{
graph[rowBegin + edge / 2 - 1][columnBegin + edge / 2 - 1] = *countp + 1;
graph[rowBegin + edge / 2][columnBegin + edge / 2 - 1] = *countp + 1;
}
else
{
graph[rowBegin + edge / 2 - 1][columnBegin + edge / 2] = *countp + 1;
graph[rowBegin + edge / 2][columnBegin + edge / 2] = *countp + 1;
}
(*countp)++;
//将原问题划分为子问题递归求解
fun(graph,rowBegin, columnBegin, edge / 2, countp);
fun(graph,rowBegin, columnBegin + edge / 2, edge / 2, countp);
fun(graph,rowBegin + edge / 2, columnBegin, edge / 2, countp);
fun(graph,rowBegin + edge / 2, columnBegin + edge / 2, edge / 2, countp);
}
}