编程之美1.15节:构造数独算法-回溯法和置换法

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	9	7	3	5	4	2	6	
7	3	5	4	2	6	1	8	9	
4	2	6	1	8	9	7	3	5	
8	9	1	3	5	7	2	6	4	
3	5	7	2	6	4	8	9	1	
2	6	4	8	9	1	3	5	7	
9	1	8	5	7	3	6	4	2	
5	7	3	6	4	2	9	1	8	
6	4	2	9	1	8	5	7	3	


评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值