编程之美1.15——构造数独

推荐http://blog.csdn.net/hustspy1990/article/details/7464698

http://blog.csdn.net/linyunzju/article/details/7673959

http://blog.csdn.net/erorr/article/details/5902385

问题:

构造一个9*9的方格矩阵,玩家要在每个方格中,分别填上1至9的任意一个数字,
让整个棋盘每一列、每一行以及每一个3*3的小矩阵中的数字都不重复。


1. 回溯法-程序

/**回溯法
 * 生成数独矩阵
 * From 编程之美1.15
*/

#include <stdio.h>
#include <time.h>

/*要生成的数独矩阵个数*/
#define SUDOKU_NUM 1

/**
 * 函数is_digital_match
 * 检测sudoku[i][j]上的值是否符合要求
*/
int is_digital_match(int sudoku[][9], int i, int j)
{
	int temp = sudoku[i][j];
	int p, q;
	int m, n;
	
	for(p=0; p<9; p++)
		if(p!=i && sudoku[p][j]==temp)
			return 0;
	for(p=0; p<9; p++)
		if(p!=j && sudoku[i][p]==temp)
			return 0;

	p = i/3;
	q = j/3;
	for(m=p*3; m<p*3+3; m++)
		for(n=q*3; n<q*3+3; n++)
			if(m!=i && n!=j && sudoku[m][n]==temp)
				return 0;
	
	return 1;
}

/*输出数独矩阵*/
void sudoku_print(int sudoku[][9])
{
	int i,j;
	for(i=0; i<9; i++)
	{
		for(j=0; j<9; j++)
			printf("%4d", sudoku[i][j]);
		printf("\n");
	}
}

int main(void)
{
    int sudoku[9][9] = {0};
    int i, j, temp=0;
    int k=0, num=0;

	srand(time(0));
	for(i=0; i<9; i++)
		for(j=0; j<9; j++)
			sudoku[i][j] = 0;
	/*通过添加一些随机性,来每次生成不同的数独矩阵*/
	/*添加更多随机性,则生成的矩阵将更随即*/
    for(i=0; i<9; i++)
	{
		temp = rand() % 81;
		sudoku[temp/9][temp%9] = i+1;
	}
	/*回溯法,构造数独矩阵*/
    while(1)
    {
        i = k/9;
        j = k%9;

		while(1)
		{
			sudoku[i][j]++;
			if(sudoku[i][j] == 10)
			{
				sudoku[i][j] = 0;
        		--k;
				break;
			}
			else if(is_digital_match(sudoku, i, j) == 1)
			{
				++k;
				break;
			}
		}

		if(k == 81)
		{
			printf("Proper sudoku matrix %d: \n", ++num);
			sudoku_print(sudoku);
			if(num >= SUDOKU_NUM)
				return 0;

			--k;
		}
    }
	
    return 0;
}

输出结果:

Proper sudoku matrix 1: 
   2   1   4   5   6   7   9   3   8
   3   5   7   1   8   9   2   4   6
   6   8   9   4   2   3   1   5   7
   4   2   1   3   7   5   8   6   9
   8   6   3   2   9   1   4   7   5
   7   9   5   6   4   8   3   1   2
   5   3   6   8   1   2   7   9   4
   1   7   8   9   5   4   6   2   3
   9   4   2   7   3   6   5   8   1

2. 置换的方法

/**简单方法
 * 快速的构造数独矩阵的算法
 * From:编程之美1.15节
 * 通过置换,来生成矩阵
*/

#include <stdio.h>
#include <time.h>

int main()
{
    int ini_matrix[3][3];    /*最初的3*3的小格子,用于生成9*9的大格子*/
    int sudoku[9][9] = {0};
    int i,j;

    for(i=0; i<3; i++)
    {
        for (j=0; j<3; j++)
        {
            ini_matrix[i][j] = i*3+j+1;
        }
    }
    /*设置随机数种子*/
    srand(time(0));
    for(i=0; i<9; i++)
    {
        int temp = rand() % 9;
        j = ini_matrix[i/3][i%3];
        ini_matrix[i/3][i%3] = ini_matrix[temp/3][temp%3];
        ini_matrix[temp/3][temp%3] = j;
    }

    printf("Initial matrix:\n");
    for(i=0; i<3; i++)
    {
        for (j=0; j<3; j++)
        {
            printf("%d\t", ini_matrix[i][j]);
        }
        printf("\n");
    }

    /*Put the ini_matrix to the center of sudoku*/
    for(i=0; i<3; i++)
    {
        for (j=0; j<3; j++)
        {
            sudoku[i+3][j+3] = ini_matrix[i][j];
            if(i==0)
            {
                sudoku[i+4][j] = ini_matrix[i][j];
                sudoku[i+5][j+6] = ini_matrix[i][j];
            }
            else if(i==1)
            {
                sudoku[i+4][j] = ini_matrix[i][j];
                sudoku[i+2][j+6] = ini_matrix[i][j];
            }
            else
            {
                sudoku[i+1][j] = ini_matrix[i][j];
                sudoku[i+2][j+6] = ini_matrix[i][j];
            }

            if(j==0)
            {
                sudoku[i][j+4] = ini_matrix[i][j];
                sudoku[i+6][j+5] = ini_matrix[i][j];
            }
            else if(j==1)
            {
                sudoku[i][j+4] = ini_matrix[i][j];
                sudoku[i+6][j+2] = ini_matrix[i][j];
            }
            else
            {
                sudoku[i][j+1] = ini_matrix[i][j];
                sudoku[i+6][j+2] = ini_matrix[i][j];
            }
        }
    }

    for(i=3; i<6; i++)
    {
        for (j=0; j<3; j++)
        {
            if(j==0)
            {
                sudoku[i-3][j+1] = sudoku[i][j];
                sudoku[i+3][j+2] = sudoku[i][j];
            }
            else if(j==1)
            {
                sudoku[i-3][j+1] = sudoku[i][j];
                sudoku[i+3][j-1] = sudoku[i][j];
            }
            else
            {
                sudoku[i-3][j-2] = sudoku[i][j];
                sudoku[i+3][j-1] = sudoku[i][j];
            }
        }
    }

    for(i=3; i<6; i++)
    {
        for (j=6; j<9; j++)
        {
            if(j==6)
            {
                sudoku[i-3][j+1] = sudoku[i][j];
                sudoku[i+3][j+2] = sudoku[i][j];
            }
            else if(j==7)
            {
                sudoku[i-3][j+1] = sudoku[i][j];
                sudoku[i+3][j-1] = sudoku[i][j];
            }
            else
            {
                sudoku[i-3][j-2] = sudoku[i][j];
                sudoku[i+3][j-1] = sudoku[i][j];
            }
        }
    }

    printf("Final matrix:\n");
    for(i=0; i<9; i++)
    {
        for (j=0; j<9; j++)
        {
            printf("%d\t", sudoku[i][j]);
        }
        printf("\n");
    }

    return 0;
}

输出结果:

Initial matrix:
3 5 7
2 6 4
8 9 1
Final matrix:
1 8 97 3 5 4 26
7 3 54 2 6 1 89
4 2 61 8 9 7 35
8 9 13 5 7 2 64
3 5 72 6 4 8 91
2 6 48 9 1 3 57
9 1 85 7 3 6 42
5 7 36 4 2 9 18
6 4 29 1 8 5 73

首先我们通过一个深度优先搜索来生成一个可行解,然后随机删除一定数量的数字,
以生成一个数独。

#include <iostream>
#include <cstdlib>
using namespace std;

#define LEN 9
#define CLEAR(a) memset((a), 0, sizeof(a))

int level[] = {30, 37, 45};

int grid[LEN+1][LEN+1];
int value[LEN+1];

void next(int &x, int &y)
{
	x++;
	if (x>9)
	{
		x = 1;
		y++;
	}
}

// 选择下一个有效状态
int pickNextValidValue(int x, int y, int cur)
{
	CLEAR(value);
	int i, j;
	for (i=1; i<y; i++)
		value[grid[i][x]] = 1;
	for (j=1; j<x; j++)
		value[grid[y][j]] = 1;
	int u = (x-1)/3*3 + 1;
	int v = (y-1)/3*3 + 1;
	for (i=v; i<v+3; i++)
		for (j=u; j<u+3; j++)
		{
			value[grid[i][j]] = 1;
		}
	for (i=cur+1; i<=LEN && value[i]; i++);
	return i;
}

void pre(int &x, int &y)
{
	x--;
	if (x<1)
	{
		x = 9;
		y--;
	}
}

int times = 0;

int main()
{
	int x, y, i, j;
	x = y = 1;
	// 深度搜索的迭代算法
	while (true)
	{
		times++;
		// 满足成功结果
		if (y==LEN && x==LEN)
		{
			for (i=1; i<=LEN; i++)
			{
				for (j=1; j<=LEN; j++)
					cout << grid[i][j] << " ";
				cout << endl;
			}
			cout << times << endl;
			break;
			//pre(x, y);
			//times = 0;
		}
		// 满足失败结果
		if (y==0)
			break;
		// 改变状态
		grid[y][x] = pickNextValidValue(x, y, grid[y][x]);
		if (grid[y][x] > LEN)
		{
			// 恢复状态
			grid[y][x] = 0;
			pre(x, y);
		}
		else
			// 进一步搜索
			next(x,y);
	}
	for (i=1; i<= level[2]; i++)
	{
		int ind = rand()%(LEN*LEN);
		grid[ind/LEN+1][ind%LEN] = 0;
	}
	for (i=1; i<=LEN; i++)
	{
		for (j=1; j<=LEN; j++)
			cout << grid[i][j] << " ";
		cout << endl;
	}
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值