递归题目练习---数独问题

数独问题

题目描述

数独是一个非常有名的游戏。整个是一个9X9的大宫格,其中又被划分成9个3X3的小宫格。要求在每个小格中放入1-9中的某个数字。要求是:每行、每列、每个小宫格中数字不能重复。 现要求用计算机求解数独。(50分)

输入描述:
输入9行,每行为空格隔开的9个数字,为0的地方就是需要填充的数字。
输出描述:
输出九行,每行九个空格隔开的数字,为解出的答案。

基本思路

需要判断同一列同一行以及同一个九宫格的数值是否有重复,如果有冲突,则需要进行下一个数值的尝试。如果此次没有找到合适的数值,则需要作出栈操作,也就是回溯到上一级。在上一级的基础数值上再进行尝试,请勿再重新头开始。否则从1开始尝试,可以尝试出一个值;但是当处理下一个数值时发现有冲突,需要进行出栈操作。但此时又从1开始尝试,第一次尝试出的值还是之前那个值,此时处理下一个数值还是会发生冲突,也就是无法绕开出现矛盾的那个数值,从而造成了死循环,无法正常得到结果。

代码如下
#include <stdio.h>

int main()
{
    int test[9][9] = {
        0,9,0,0,0,0,0,6,0,
        8,0,1,0,0,0,5,0,9,
        0,5,0,3,0,4,0,7,0,
        0,0,8,0,7,0,9,0,0,
        0,0,0,9,0,8,0,0,0,
        0,0,6,0,2,0,7,0,0,
        0,8,0,7,0,5,0,4,0,
        2,0,5,0,0,0,8,0,7,
        0,6,0,0,0,0,0,9,0,
    };
    int i,j;
    int data[81][2] = {0};	//存储待处理的坐标二维数组,最多需要处理81个数据 
    int count = 0;			//记录待处理的坐标,count表示需处理的坐标总数
    
    for(i = 0; i < 9; i++){
        for(j = 0; j < 9; j++){
            if(test[i][j] == 0){
                data[count][0] = i;
                data[count][1] = j;
                count++;
            }          
        }
    }
    printf("count = %d\n",count);
    
    int okflag = 1;
    int nowstep = 0;	//nowstep指示当前处理的待处理位置,nowstep==0为第一个,nowstep==count-1为最后一个
    int n = 0;
    int si,sj;
    while(nowstep < count){
        si = data[nowstep][0];
        sj = data[nowstep][1];    
    //	n = 1; 					
	    n = test[si][sj];        //每次都从当前数继续,因为下面有test[si][sj] = n;一步,表示前面的已不合适,所以没必要再从1开始,会造成矛盾。
	//	okflag = 1;
	  
        //冲突检测
        while(n <= 9){ 
			okflag = 1;			//每一次标志需要重新设置 
            for(i = 0; i < 9; i++){
                for(j = 0; j < 9; j++){
             	   //冲突检测,此举代码表示当处于检测区域时,如果已经出现n,则表示存在冲突,此时需要进行下一步的检测
					//而当检测区域既不处于同一行,也不属于同一列,同时也不属于同一个方格时
					//s==i||t==j||((s/3)*3+t/3)==((i/3)*3+j/3)为0,也就没有检测的必要了,减少检测的次数。
					//而当处于同一行列和一个方框时,必须要检测是否已经存在的数值n。
    //            	if(i == si||j == sj||(((i/3)*3 + j/3)==((si/3)*3 + sj/3))&&test[i][j] == n){
                    if((i == si||j == sj||(((i/3)*3 + j/3)==((si/3)*3 + sj/3)))&&test[i][j] == n){
						okflag = 0;	//发生冲突,退出
						break;
                    }            
                }
                if(okflag == 0){	//发生冲突,n++继续尝试 
					break;
                }
            }
            if(okflag == 1){		//当前值可用,退出n值尝试的while循环
            	break;
            } 
            n++;
			          
        }
        //如果标志为1,表示当前n值可以入栈,然后操作下一个为0的数独处
        if(okflag == 1){
            test[si][sj] = n;
            nowstep++;
        }
        //如果标志为0,表示当前n值有冲突,需要出栈处理,初始化当前冲突除为0,相当于没有检测此步
        else if(okflag == 0){
        	test[si][sj] = 0; 
            nowstep--;
        }     
    }
    
    //结果输出
    for(i = 0; i < 9; i++){
        for(j = 0; j < 9; j++){
            printf("%d,",test[i][j]);
        }
        printf("\n");
    }

    return 0;
}

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Clichong

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值