计算机求解数独问题S

《算法的乐趣》中数独的求解

// Sudoku.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <set>
#include <iostream>

using namespace std;

#define SKD_ROW_LIMET 9
#define SKD_COL_LIMET SKD_ROW_LIMET
#define SKD_CELL_COUNT (SKD_COL_LIMET)*(SKD_ROW_LIMET)

// 数独单元格结构;
typedef struct stSDKCell
{
	int num;	// 单元格值;
	bool fixed; // 是否固定;
	set<int> candidators; // 候选列表;
	stSDKCell()
	{
		num = 0;
		fixed = false;
		for ( int i = 1; i <= 9; i++ )
		{
			candidators.insert(i);
		}
	}
}SUDUKU_CELL;

// 数独整体结构;
typedef struct stSDKGame 
{
	SUDUKU_CELL cells[SKD_ROW_LIMET][SKD_COL_LIMET];
	int fixedCount;
	stSDKGame()
	{
		fixedCount = 0;
	}
}SUDUKU_GAME;

int SkipFixedCell( SUDUKU_GAME *pGame, int sp ); // 找到下一个未填充单元;
void CopyGameState( SUDUKU_GAME *pGame, SUDUKU_GAME *pnew_state ); // 数独结构深拷贝;
void PrintSudokuGame( SUDUKU_GAME *pGame ); // 打印数独解;
void SwitchCellToFiexed( SUDUKU_GAME *pGame, int row, int col, int num ); // 数独单元赋值并锁定;
set<int> FindRelatedCells( int row, int col ); // 当前(row,col)的相关单元;
bool ExclusiveCorrelative( SUDUKU_GAME *pGame, int row, int col, int num ); // 调整候选值范围;
bool ProcessSinglesCandidature( SUDUKU_GAME *pGame, int row, int col, int num ); // 单元候选值唯一的处理;
bool SetCandidatorTofixed( SUDUKU_GAME *pGame, int row, int col, int num ); // 试探性对数独单元锁值;


// 找出数独解决方案;
void FindSudokuSolution( SUDUKU_GAME *pGame, int sp )
{
	if ( pGame->fixedCount == SKD_CELL_COUNT )
	{
		cout << "Find result :" << endl;
		PrintSudokuGame( pGame );
	}

	sp = SkipFixedCell( pGame, sp );
	if ( sp >= SKD_CELL_COUNT )
	{
		return;
	}

	int row = sp / SKD_COL_LIMET;
	int col = sp % SKD_COL_LIMET;
	SUDUKU_CELL *curCell = &pGame->cells[row][col];
	SUDUKU_GAME new_state;
	for ( auto iter = curCell->candidators.begin(); iter != curCell->candidators.end(); ++iter )
	{
		CopyGameState( pGame, &new_state );
		if ( SetCandidatorTofixed( &new_state, row, col, *iter ) )
		{
			FindSudokuSolution( &new_state, sp + 1 );
		}
	}
}

// 数独单元赋值并锁定;
void SwitchCellToFiexed( SUDUKU_GAME *pGame, int row, int col, int num )
{
	SUDUKU_CELL& cell = pGame->cells[row][col];
	cell.num = num;
	cell.fixed = true;
}

// 当前(row,col)的相关单元;
set<int> FindRelatedCells( int row, int col )
{
	set<int> cells;
	// 相关行;
	for ( int iCol = 0; iCol < SKD_COL_LIMET; iCol++ )
	{
		cells.insert( row * SKD_COL_LIMET + iCol );
	}
	// 相关列;
	for ( int iRow = 0; iRow < SKD_ROW_LIMET; iRow++ )
	{
		cells.insert( iRow * SKD_COL_LIMET + col );
	}
	// 九宫格;
	int iRowS = row / 3 * 3;
	int iColS = col / 3 * 3;
	for ( int iRow = iRowS; iRow < iRowS + 3; iRow++ )
	{
		for ( int iCol = iColS; iCol < iColS + 3; iCol++ )
		{
			cells.insert( iRow * SKD_COL_LIMET + iCol );
		}
	}

	return cells;
}

// 调整候选值范围;
bool ExclusiveCorrelative( SUDUKU_GAME *pGame, int row, int col, int num )
{
	set<int> cells = FindRelatedCells( row, col);
	for ( auto iter = cells.begin(); iter != cells.end(); ++iter )
	{
		int iRow = *iter / SKD_COL_LIMET;
		int iCol = *iter % SKD_COL_LIMET;
		SUDUKU_CELL& cell = pGame->cells[iRow][iCol];
		if ( cell.fixed )
		{
			continue;
		}
		else
		{   
			auto valIter = cell.candidators.find( num );
			if ( cell.candidators.end() != valIter )
			{
				cell.candidators.erase( valIter );
				if ( cell.candidators.empty() )
				{
					return false;
				}
			}
		}
	}

	return true;
}

// 单元候选值唯一的处理;
bool ProcessSinglesCandidature( SUDUKU_GAME *pGame, int row, int col, int num )
{
	set<int> cells = FindRelatedCells( row, col);

	for ( auto iter = cells.begin(); iter != cells.end(); ++iter )
	{
		int iRow = *iter / SKD_COL_LIMET;
		int iCol = *iter % SKD_COL_LIMET;
		SUDUKU_CELL& cell = pGame->cells[iRow][iCol];
		if ( !cell.fixed && cell.candidators.size() == 1 )
		{
			int iNum = *( cell.candidators.begin() );
			if ( !SetCandidatorTofixed( pGame, iRow, iCol, iNum ) )
			{
				return false;
			}
		}
	}

	return true;
}

// 试探性对数独单元锁值;
bool SetCandidatorTofixed( SUDUKU_GAME *pGame, int row, int col, int num )
{
	SwitchCellToFiexed( pGame, row, col, num );

	if ( !ExclusiveCorrelative( pGame,row,col,num ) )
	{
		return false;
	}

	if ( !ProcessSinglesCandidature( pGame, row, col, num ) )
	{
		return false;
	}

	pGame->fixedCount++;
	return true;
}

// 打印数独解;
void PrintSudokuGame( SUDUKU_GAME *pGame )
{
	for ( int i = 0; i < SKD_ROW_LIMET; ++i )
	{
		for ( int j = 0; j < SKD_COL_LIMET; ++j )
		{
			cout << pGame->cells[i][j].num << "\t";
		}
		cout << endl;
	}
}

// 找到下一个未填充单元;
int SkipFixedCell( SUDUKU_GAME *pGame, int sp )
{
	while ( sp < SKD_CELL_COUNT )
	{
		int row = sp / SKD_COL_LIMET;
		int col = sp % SKD_COL_LIMET;
		if ( !pGame->cells[row][col].fixed )
		{
			break;
		}
		else
		{
			sp++;
		}
	}

	return sp;
}

// 数独结构深拷贝;
void CopyGameState( SUDUKU_GAME *pGame, SUDUKU_GAME *pnew_state )
{
	pnew_state->fixedCount = pGame->fixedCount;
	for ( int i = 0; i < SKD_ROW_LIMET; ++i )
	{
		for ( int j = 0; j < SKD_COL_LIMET; ++j )
		{
			pnew_state->cells[i][j] = pGame->cells[i][j];
		}
	}
}

// 初始化数独已知数据;
void InitSDK( SUDUKU_GAME *pGame, int* datas )
{
	for ( int i = 0; i < SKD_ROW_LIMET; ++i )
	{
		for ( int j = 0; j < SKD_COL_LIMET; ++j )
		{
			int ps = j + i * SKD_COL_LIMET;
			if ( datas[ps] != 0 )
			{
				pGame->cells[i][j].num = datas[ps];
				pGame->cells[i][j].fixed = true;
				pGame->fixedCount++;
			}
			else
			{
				set<int> cells = FindRelatedCells( i, j );
				for ( auto iter = cells.begin(); iter != cells.end(); ++iter )
				{
					if ( datas[*iter] != 0 )
					{
						set<int>& tempSet = pGame->cells[i][j].candidators;
						auto valIter = tempSet.find( datas[*iter] );
						if ( valIter != tempSet.end() )
						{
							tempSet.erase( valIter );
							if ( tempSet.empty() )
							{
								cout << "No result!" << endl;
							}
						}						
					}
				}
			}
		}
	}
}

int _tmain(int argc, _TCHAR* argv[])
{
	int datas[SKD_CELL_COUNT] = { 0 };
	datas[0] = 8;
	datas[11] = 3;
	datas[12] = 6;
	datas[19] = 7;
	datas[22] = 9;

	datas[24] = 2;
	datas[28] = 5;
	datas[32] = 7;
	datas[40] = 4;
	datas[41] = 5;

	datas[42] = 7;
	datas[48] = 1;
	datas[52] = 3;
	datas[56] = 1;
	datas[61] = 6;

	datas[62] = 8;
	datas[65] = 8;
	datas[66] = 5;
	datas[70] = 1;
	datas[73] = 9;

	datas[78] = 4;

	SUDUKU_GAME game;
	InitSDK( &game, datas );

	FindSudokuSolution( &game, 0 );

	system("pause");

	return 0;
}

    原文作者:九宫格问题
    原文地址: https://blog.csdn.net/yi10086/article/details/80459708
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞