呵呵~~自从上次的模拟汉诺塔后~
发现用控制台来模拟或实现算法设计里的算法也是一件很有意思的事~
这次是棋盘覆盖问题~由于书上只是简单的把算法说了
如果能看到结果的棋盘可能会更好理解一点。
这里先把题目说一下:
在一个2k x 2k ( 即:2^k x 2^k )个方格组成的棋盘中,恰有一个方格与其他方格不同,称该方格为一特殊方格,且称该棋盘为一特殊棋盘。在棋盘覆盖问题中,要用图示的4种不同形态的L型骨牌覆盖给定的特殊棋盘上除特殊方格以外的所有方格,且任何2个L型骨牌不得重叠覆盖。
由于所能控制台能显示的颜色有限,所以难免有些L型方块的颜色会一样~
可以通过修改size的值来修改棋盘的大小,注意只能修改为4,8,16其中之一,改为32时显示会超过控制台的显示范围,造成结果不清晰。修改dr,dc来修改特殊方块的位置。
代码在VC2008下编译通过,如果在VC6.0下只要将#include "stdafx.h"以及修改main函数的函数名即可。
代码如下:
// 棋盘覆盖.cpp : 定义控制台应用程序的入口点。 // #include <iomanip> #include <iostream> #include <Windows.h> using namespace std; ////////////////////////////////////////////////////////////////////////// // 全局数据 int tile = 1; // L型骨牌的编号 const int size = 8; // 2^k,棋盘规格为2^k * 2^k,即size * size(只能选4,8,16) const int dr = 3; // 特殊方格所在的行号 const int dc = 5; // 特殊方格所在的列号 int board[size][size]; // 棋盘 ////////////////////////////////////////////////////////////////////////// // 函数 /* 求解棋盘覆盖问题 */ void chessBoard(const int tr, // 棋盘左上角方格的行号 const int tc, // 棋盘左上角方格的列号 const int dr, // 特殊方格所在的行号 const int dc, // 特殊方格所在的列号 int size // 棋盘大小 ); /* 打印棋盘 */ void PrintChessBoard(); /* 主函数 */ int main() { /* 初始化棋盘(所有值改为0) */ memset(board, 0, sizeof(int) * size * size); /* 为了突出特殊方块,先将其改为1,计算时要改为0 */ board[dr][dc] = 1; /* 显示初始的棋盘 */ cout<<"原始棋盘为:(其中1代表特殊方块)"<<endl<<endl; PrintChessBoard(); cout<<endl; board[dr][dc] = 0; /* 覆盖棋盘 */ chessBoard(0, 0, dr, dc, size); /* 显示结果棋盘 */ cout<<"结果棋盘为:"<<endl<<endl; PrintChessBoard(); cout<<endl; return 0; } /* 覆盖开始位置为board[tr][tc],大小为size的子棋盘 */ void chessBoard(const int tr, const int tc, const int dr, const int dc, int size) { /* 大小为1则不用覆盖 */ if (size == 1) { return ; } /* L型骨牌号*/ int t = tile++; /* 分割棋盘 */ int s = size / 2; /********** 覆盖左上角棋盘 **********/ if (dr < tr + s && dc < tc + s) { /* 特殊方格在此棋盘中 */ chessBoard(tr, tc, dr, dc, s); } else { /* 此棋盘中无特殊方格 */ /* 用t号L型骨牌覆盖右下角 */ board[tr + s - 1][tc + s - 1] = t; /* 覆盖其余方格 */ chessBoard(tr, tc, tr + s - 1, tc + s - 1, s); } /********** 覆盖右上角棋盘 **********/ if (dr < tr + s && dc >= tc + s) { /* 特殊方格在此棋盘中 */ chessBoard(tr, tc + s, dr, dc, s); } else { /* 此棋盘中无特殊方格 */ /* 用t号L型骨牌覆盖左下角 */ board[tr + s - 1][tc + s] = t; chessBoard(tr, tc + s, tr + s - 1, tc + s, s); } /********** 覆盖左下角棋盘 **********/ if (dr >= tr + s && dc < tc + s) { /* 特殊方格在此棋盘中 */ chessBoard(tr + s, tc, dr, dc, s); } else { /* 此棋盘中无特殊方格 */ /* 用t号L型骨牌覆盖右上角 */ board[tr + s][tc + s - 1] = t; /* 覆盖其余方格 */ chessBoard(tr + s, tc, tr + s, tc + s - 1, s); } /********** 覆盖右下角棋盘 **********/ if (dr >= tr + s && dc >= tc + s) { /* 特殊方格在此棋盘中 */ chessBoard(tr + s, tc + s, dr, dc, s); } else { /* 此棋盘中无特殊方格 */ /* 用t号L型骨牌覆盖左上角 */ board[tr + s][tc + s] = t; /* 覆盖其余方格 */ chessBoard(tr + s, tc + s, tr + s, tc + s, s); } } /* 打印棋盘 */ void PrintChessBoard() { /* 得到控制台显示句柄 */ HANDLE hScreen = GetStdHandle(STD_OUTPUT_HANDLE); int i, j; for (i=0; i<size; i++) { for (j=0; j<size; j++) { /* 控制台可显示8种背景颜色和8种字体颜色 */ /* 背景颜色为0x0000 - 0x0070,增量为0x0010 */ /* 字体颜色为0x0000 - 0x0007,增量为0x0001 */ /* 下面这种办法可使背景颜色与字体颜色互为相反色 */ WORD bgColor = 0x0070 - 0x0010 * (board[i][j] % 8); WORD foColor = 0x0000 + 0x0001 * (board[i][j] % 8); SetConsoleTextAttribute(hScreen, foColor | bgColor); /* 要使输出结果矩阵元素对齐,需要补空格 */ if (board[i][j] < 10) { cout<<board[i][j]<<" "; } else { cout<<board[i][j]<<" "; } } cout<<endl; } /* 重设回原来的颜色 */ /* FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_GREEN 即为字体白色,对应0x0007 */ /* 0 即为背景黑色 */ SetConsoleTextAttribute(hScreen, FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_GREEN | 0); }