Project Euler 96 Sudoku

Su Doku

Problem 96

Su Doku (Japanese meaning number place) is the name given to a popular puzzle concept. Its origin is unclear, but credit must be attributed to Leonhard Euler who invented a similar, and much more difficult, puzzle idea called Latin Squares. The objective of Su Doku puzzles, however, is to replace the blanks (or zeros) in a 9 by 9 grid in such that each row, column, and 3 by 3 box contains each of the digits 1 to 9. Below is an example of a typical starting puzzle grid and its solution grid.

0 0 3
9 0 0
0 0 1
0 2 0
3 0 5
8 0 6
6 0 0
0 0 1
4 0 0
0 0 8
7 0 0
0 0 6
1 0 2
0 0 0
7 0 8
9 0 0
0 0 8
2 0 0
0 0 2
8 0 0
0 0 5
6 0 9
2 0 3
0 1 0
5 0 0
0 0 9
3 0 0
4 8 3
9 6 7
2 5 1
9 2 1
3 4 5
8 7 6
6 5 7
8 2 1
4 9 3
5 4 8
7 2 9
1 3 6
1 3 2
5 6 4
7 9 8
9 7 6
1 3 8
2 4 5
3 7 2
8 1 4
6 9 5
6 8 9
2 5 3
4 1 7
5 1 4
7 6 9
3 8 2

A well constructed Su Doku puzzle has a unique solution and can be solved by logic, although it may be necessary to employ "guess and test" methods in order to eliminate options (there is much contested opinion over this). The complexity of the search determines the difficulty of the puzzle; the example above is considered easy because it can be solved by straight forward direct deduction.

The 6K text file, sudoku.txt (right click and 'Save Link/Target As...'), contains fifty different Su Doku puzzles ranging in difficulty, but all with unique solutions (the first puzzle in the file is the example above).

By solving all fifty puzzles find the sum of the 3-digit numbers found in the top left corner of each solution grid; for example, 483 is the 3-digit number found in the top left corner of the solution grid above.

    大意就是解数独了。这道题前前后后做了大概也有几天(因为学业繁忙,专门用来思考的时间倒是不多)。一开始我的想法就是,像人类解数独那样,教计算机用逻辑去分析,但这样要枚举的情况实在太多,而且还不能用一个通式写出来,编写程序十分麻烦。

    后来才想到应该用计算的思维去解决这个问题。因为计算机擅长计算,而不是去分析哪个地方最好当突破口等等。于是我们可以考虑,每个空白格都有可能填进1~9的某个数字,按照一定的顺序去填满这些空格子,就构成了一棵巨大无比的树。(如果这个数独有20个已经被填好的数,那么这个树的大小是9^61)

    虽然这棵树非常庞大,不过很好的一点是,如果我们否定了一棵树的一个节点,那么它的子树也将被否定,这样这个问题就变成了一个“砍树”的问题。于是思路就呼之欲出:

    指定一个填数的序列,从这个序列开始移动,相当于树的先序遍历。遇到不符合数独规则的情况,就将这个子树给砍掉,写成代码是这个样子:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>


static FILE *fp;

void duru(char sudoku[][9]) {
	char str[13]={0};
	for (int i=0;i<10;i++) {
		fgets(str,13,fp);
		if (i!=0) {
			for (int j=0;j<9;j++) {
				sudoku[i-1][j]=str[j];
			}
		}
		memset(str,0,13);
	}
}  //测试正确 


//return 1 if the sudoku is right 
int judge(char sudoku[][9]) {
	int ret=1,hash[10]={0};
	for (int i=0;i<9;i++) {
		memset(hash,0,10*sizeof(int));		
		for (int j=0;j<9;j++) {
			hash[sudoku[i][j]-'0']++;
		}
		for (int k=1;k<10;k++) {
			if (hash[k]>1) {
//				ret = 0;
//				break;
				return 0;
			}
		}
	}    //check row
	
	for (int i=0;i<9;i++) {
		memset(hash,0,10*sizeof(int));		
		for (int j=0;j<9;j++) {
			hash[sudoku[j][i]-'0']++;
		}
		for (int k=1;k<10;k++) {
			if (hash[k]>1) {
//				ret = 0;
//				break;
				return 0;
			}
		}
	}    //check column
	
	for (int i=0;i<9;i+=3) {
		for (int j=0;j<9;j+=3) {
			
			memset(hash,0,10*sizeof(int));
			for (int i1=i;i1<i+3;i1++) {
				for (int j1=j;j1<j+3;j1++) {
					hash[sudoku[i1][j1]-'0']++;
				}
			}
			
			for (int k=1;k<10;k++) {
				if (hash[k]>1) {
					return 0;
				}
			}
		}
	}
	
	return 1;
	
}


// return 1 stands for end
int forward(int *pi,int *pj,char map[][9]) {
	int ret=0;
	(*pj)++;
	if (*pj>=9) {
		(*pj)-=9;
		(*pi)++;
	}
	while (map[*pi][*pj]==1) {
		(*pj)++;
		if (*pj>=9) {
			(*pj)-=9;
			(*pi)++;
		}
		if (*pi==8&&*pj==8) {
			ret=1;
			break;
		}
	}
	return ret;
}

//0 stands for error
int back(int *pi,int *pj,char map[][9]) {
	int ret=1;
	(*pj)--;
	if (*pi<0) {
		(*pj)+=9;
		(*pi)--;
	}
	
	while (map[*pi][*pj]==1) {
		(*pj)--;
		if (*pi<0) {
			(*pj) += 9;
			(*pi)--;
		}
		
		if (*pi==-1&&(*pj)!=8) {
			ret = 0;
			break;
		}
	}
	
	return ret;
	
}

void findend(int *pi,int *pj,char map[][9]) {
	for (int i=0;i<9;i++) {
		for (int j=0;j<9;j++) {
			if (!map[i][j]) {
				*pi = i;
				*pj = j;
			}
		}
	}
}

void solve(char sudoku[][9]) {
	int indexi=-1,indexj=8,isback=0,endi,endj;
	char map[9][9]={0};
	
	
	for (int i=0;i<9;i++) {
		for (int j=0;j<9;j++) {
			if (sudoku[i][j]!='0') map[i][j]=1;
		}
	}  // 注明已知条件 
	
	findend(&endi,&endj,map);
	
	do {
		
		if (judge(sudoku)&&(indexi!=endi||indexj!=endj)) {
			forward(&indexi,&indexj,map);
			sudoku[indexi][indexj] = '1';
		}
		
		if (judge(sudoku)==0) {
			while (sudoku[indexi][indexj]=='9') {
				sudoku[indexi][indexj] = '0';
				back(&indexi,&indexj,map);
			}
			sudoku[indexi][indexj]++;
		}
		
		if (judge(sudoku)&&(indexi==endi)&&indexj==endj) break;
		
	} while (1);
	
	
}



int main() {
	char sudoku[9][9]={0}; 
	int ans = 0; 
	fp=fopen("2.txt","r");
	for (int lp=1;lp<=50;lp++) {
	
		duru(sudoku);
		solve(sudoku);
		
		for (int i=0;i<9;i++) {
			for (int j=0;j<9;j++) {
				printf("%c",sudoku[i][j]);
			}
			printf("\n");
		}
		
		ans += (sudoku[0][0]-'0')*100 + (sudoku[0][1]-'0')*10 +(sudoku[0][2]-'0');
		
		for (int i=0;i<9;i++) {
			for (int j=0;j<9;j++) {
				sudoku[i][j]=0;
			}
		} // initialized the sudoku
		
		
		printf("\n");
	}
	printf("%d\n",ans);
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。
1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值