数独问题

数独问题



样例输出

145327698

839654127

672918543

496185372

218473956

753296481

367542819

984761235

521839764


解法1(按坐标):

数独问题(以列为主):
 
都是同一行、同一列以及在小矩阵中不存在与之相同而且当前位置没有被放置数字也就是此处为0;
其中,确定该位置所在的小矩阵是根据其所在小矩阵的左上角坐标而定,
 
因为是根据坐标进行回溯所以起始为(0,0)~(n-1,n-1)
当(x==n && y==n)时到达解空间,此时的矩阵是满足条件的

当回溯到一个位置时有两种可能:
(1)此处已经存在数字,
①如果是最后一列并且是最后一行,直接输出该结果
②如果是最后一列不是最后一行,进行当前列下一行的位置traceback(x+1,y);
③如果不是最后一列,是最后一行则 traceback(0,y+1); 
④如果既不是最后一列又不是最后一行则traceback(x+1,y) 
(2)此处没有数字
首先应该将此位置进行赋值,该位置可以放置 1~n 
放置数字之后进行判断该数字放在此处是否合适,如果合适则进行如上4步判断
如果不合适,则放置下一数字。 


#include <stdio.h> 
#define n 9
int a[n][n]={
0,0,5,3,0,0,0,0,0,
8,0,0,0,0,0,0,2,0,
0,7,0,0,1,0,5,0,0,
4,0,0,0,0,5,3,0,0,
0,1,0,0,7,0,0,0,6,
0,0,3,2,0,0,0,8,0,
0,6,0,5,0,0,0,0,9,
0,0,4,0,0,0,0,3,0,
0,0,0,0,0,9,7,0,0};

bool ok(int x, int y) //二者分别是数组对应的行地址和列地址,取值为0-8  
{  
    int up, down, left, right;  
    int i,j;  
  
    up=x/3*3;  
    down=up+3;  
  
    left=y/3*3;  
    right=left+3;  
  
    //以下分三种情况判断是否在x,y对应的位置放这个数,如果不可以放,返回0,如果可以放,返回1,会进一步迭代  
      
    for(i=0;i<9;i++){  
        if(a[x][y]==a[i][y] && i!=x && a[i][y]!=0)  
            return false;         
    }  
  
    for(i=0;i<9;i++){  
        if (a[x][y]==a[x][i] && i!=y && a[x][i]!=0)  
            return false;         
    }  
  
    for(i=up;i<down;i++)  
    {  
        for(j=left;j<right;j++)  
            if(i!=x || j!=y)  
            {  
                if(a[i][j]==a[x][y] && a[i][j]!=0)  
                    return false;  
            }  
    }  
  
    return true;     
}  
void traceback(int x,int y){//按a[x][y]的坐标回溯 
	if(a[x][y]!=0){
		if(y==n-1){
			if(x==n-1){
				printf("=============\n");
				for (int i=0; i<9; i++) {
            		for (int j =0; j <9; j++) {
                		printf("%d ",a[i][j]);
            		}
            		printf("\n");
        		}
       		}
        	else
				traceback(x+1,y);
		}
		else{
			if(x==n-1)	
				traceback(0,y+1);
			else 
				traceback(x+1,y);
		}
	}
	else{
		for(int i=1;i<10;i++){
			a[x][y]=i;
			if(ok(x,y)){//如果可以放 
				if(y==n-1){
					if(x==n-1){
						for (int i=0; i<9; i++) {
		            		for (int j =0; j <9; j++) {
		                		printf("%d ",a[i][j]);
		            		}
		            		printf("\n");
		        		}
		       		}
		        	else
						traceback(x+1,y);
				}
				else{
					if(x==n-1)	
						traceback(0,y+1);
					else 
						traceback(x+1,y);
				}
			}
			a[x][y]=0;
		}
		
	}
		
} 
	


int main()
{
   traceback(0,0);  
	return 0;
}

解法2(按编号):

矩阵的判断与按坐标回溯相同。
 
按照编号进行回溯的时候,一共 n*n 个位置所以当 t==n*n 时到达解空间直接输出矩阵结果 
此时位置的坐标变成了:x=t/9; y=t%9;
当不到解空间时有两种可能:
(1)此处已经存在数字,
直接进行下一位置的判断 
(2)此处没有数字
首先应该将此位置进行赋值,该位置可以放置 1~n 
放置数字之后进行判断该数字放在此处是否合适,如果合适则进行下一位置的判断(dfs(t+1)) 
如果不合适,则放置下一数字。  


#include <stdio.h> 
#define n 9

int a[n][n]={
0,0,5,3,0,0,0,0,0,
8,0,0,0,0,0,0,2,0,
0,7,0,0,1,0,5,0,0,
4,0,0,0,0,5,3,0,0,
0,1,0,0,7,0,0,0,6,
0,0,3,2,0,0,0,8,0,
0,6,0,5,0,0,0,0,9,
0,0,4,0,0,0,0,3,0,
0,0,0,0,0,9,7,0,0};


bool ok(int x, int y) 
{  
    int up, down, left, right;  
    int i,j;  
  
    up=x/3*3;  
    down=up+3;  
  
    left=y/3*3;  
    right=left+3;   
    for(i=0;i<9;i++){  
        if(a[x][y]==a[i][y] && i!=x && a[i][y]!=0)  
            return false;         
    }  
    for(i=0;i<9;i++){  
        if (a[x][y]==a[x][i] && i!=y && a[x][i]!=0)  
            return false;         
    }  
    for(i=up;i<down;i++)  
    {  
        for(j=left;j<right;j++)  
            if(i!=x || j!=y)  
            {  
                if(a[i][j]==a[x][y] && a[i][j]!=0)  
                    return false;  
            }  
    }  
    return true;     
}

void dfs(int t)
{
	if(t==81)
	{
		for(int i=0;i<n;i++){
			for(int j=0;j<n;j++)
			{
				printf("%d ",a[i][j]);
			}
			printf("\n");
		
		} 
	}
	else{
		int x=t/9;
		int y=t%9;
		if(a[x][y]!=0)
		{
			dfs(t+1);
		}else{
			for(int i=1;i<10;i++)
			{
				a[x][y]=i;
				if(ok(x,y))
				{
					dfs(t+1);
				}
				a[x][y]=0;
			}
		}
	}
}


int main()
{
	dfs(0);
	return 0; 
}




  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值