Project Euler 96:Su Doku 数独
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.

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 consideredeasy 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.
数独(日语原意为数的位置)是一种热门的谜题。它的起源已不可考,但是与欧拉发明的一种类似而更加困难的谜题拉丁方阵之间有着千丝万缕的联系。数独的目标是替换掉9乘9网格中的空白位置(或0),使得每行、每列以及每个九宫格中恰好都包含数字1~9。如下是一个典型的数独谜题以及它的解答。

在这个6K的文本文件sudoku.txt(右击并选择“目标另存为……”)中包含有50个不同难度的数独谜题,但保证它们都只有唯一解(文件中的第一个谜题就是上述样例)。一个构造精良的数独谜题应该包含有唯一解,且能够通过逻辑推断来解决,尽管有时可能必须通过“猜测并检验”来排除一些选项(这一要求目前还颇受争议)。寻找答案的复杂度决定了题目的难度;上面这个谜题被认为是简单的谜题,因为我们可以通过直截了当的演绎推理来解决它。
解开这50个谜题,找出每个谜题解答左上角的三个数字并连接起来,给出这些数的和;举例来说,上述样例解答左上角的三个数字连接起来构成的数是483。
解题
读取数据,求解数独。
1.读数据,用Java还是比较简单的,但是最后一个数独我还是忘了,这个是由于在加入数独的时候判断条件的问题最好一个要单独加入。详细看程序
2.求解数独
数独的特点:1.每行数字只能是1到9且不能重复。2.每列数字只能是1到9且不能重复。3.数字所在的行和列只能是1到9且不能重复。
之前做过一个验证有效数独,好像可以直接拿来用,那么,怎么用?
对于没有填取数字的数独,暴露变量1-9,然后判断是否是合法的数独,然后再暴露填充下一个空的数并判断合法性。用于DFS的思想。
JAVA
package Level3; import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList; public class PE096{
public static void run() throws IOException{
ArrayList<int[][]> sudoku= getSudoku();
int[][] sd = sudoku.get(0);
int result = 0;
for(int index=0;index<sudoku.size();index++){
sd = sudoku.get(index);
solvesudoku(sd,0);
result += sd[0][0]*100+sd[0][1]*10+sd[0][2];
}
System.out.println(result);
}
// 24702
// running time=0s515ms
public static boolean solvesudoku(int[][] sd,int index){
if(index >= 81)
return true;
int x = index/9;
int y = index%9;
if(sd[x][y]==0){
for(int n=1;n<=9;n++){
sd[x][y] = n;
if(CheckrowAndcol(sd,x,y,n) && CheckGrid(sd,x,y,n))
if(solvesudoku(sd,index+1))
return true;
sd[x][y] = 0;
}
}else
return solvesudoku(sd,index+1);
return false; }
// 判断 n 所在的行列是否包含 n
public static boolean CheckrowAndcol(int[][] sd,int x ,int y,int n){
// x 行
for(int j=0;j<9;j++){
if(j!=y && sd[x][j] ==n )
return false;
}
// y列
for(int i=0;i<9;i++){
if(i!=x && sd[i][y]==n )
return false;
}
return true;
}
// 判断所在的方格是否包含 n
public static boolean CheckGrid(int[][] sd,int x,int y,int n){
// 根据x y的坐标求其所在方格的左上坐标和右下坐标表示不好想。
for(int i = (x/3)*3;i<(x/3+1)*3;i++){
for(int j=(y/3)*3;j<(y/3+1)*3;j++){
if(i!=x && j!=y && sd[i][j]==n)
return false;
}
}
return true;
}
public static ArrayList<int[][]> getSudoku() throws IOException{
ArrayList<int[][]> sudoku= new ArrayList<int[][]>();
int[][] sd = new int[9][9]; String filename = "src/Level3/p096_sudoku.txt";
BufferedReader data = new BufferedReader(new FileReader(filename));
String tmp = null;
// 第几个数独
int index = 0;
// 读取到数独的某行
int row = 0;
while((tmp=data.readLine())!=null){
String grid=tmp.substring(0,4);
if(grid.equals("Grid")){
if(index!=0){
sudoku.add(sd);
}
index++;
row =0;
sd = new int[9][9];
}else{
String[] arrayStr = tmp.trim().split("");
for(int i=0;i<9;i++){
sd[row][i] = Integer.parseInt(arrayStr[i+1]);
}
row++;
}
}
//最后一个数独
sudoku.add(sd);
return sudoku; }
public static void main(String[] args) throws IOException {
long t0 = System.currentTimeMillis();
run();
long t1 = System.currentTimeMillis();
long t = t1 - t0;
System.out.println("running time="+t/1000+"s"+t%1000+"ms"); }
}
论坛中直接复制的Python程序
# coding=gbk
import copy
import time as time
filePath = 'E:/java/projecteuler/src/Level3/p096_sudoku.txt'
dim = 9
# 判断数独的合法性
def assert_sudoku(puzzle):
# 行列
for i in range(dim):
seen_row = []
seen_col = []
for j in range(dim):
if (puzzle[i][j] and puzzle[i][j] in seen_row) or(puzzle[j][i] and puzzle[j][i] in seen_col):
return False
seen_row.append(puzzle[i][j])
seen_col.append(puzzle[j][i])
# 方格
for boxIDX in range(3):
for boxIDY in range(3):
seen = []
for boxX in range(3):
for boxY in range(3):
value = puzzle[3*boxIDX + boxX][3*boxIDY + boxY]
if value and value in seen:
return False
seen.append(value)
return True def find_empty_cell(puzzle):
empty_cells_col = [0]*dim
empty_cells_row = [0]*dim
for i in range(dim):
for j in range(dim):
if puzzle[i][j] == 0:
empty_cells_col[i] +=1
if puzzle[j][i] == 0:
empty_cells_row[i] +=1
empty_cells = []
for i in range(dim):
for j in range(dim):
if puzzle[i][j] ==0:
empty_cells.append([[i,j],min(empty_cells_row[j],empty_cells_col[i])])
if len(empty_cells) == 0:
return []
best_empty_cell = min(empty_cells, key=lambda x: x[1])
return best_empty_cell[0] def solve(puzzle):
empty_cell = find_empty_cell(puzzle) if len(empty_cell) == 0:
return puzzle for value in range(1, dim+1, 1):
new_puzzle = copy.deepcopy(puzzle)
new_puzzle[empty_cell[0]][empty_cell[1]] = value
if not assert_sudoku(new_puzzle):
continue
new_puzzle = solve(new_puzzle)
if len(new_puzzle) == 0:
continue
else:
return new_puzzle return [] def main():
file = open(filePath, "r")
data = file.readlines()
data = [row.strip() for row in data] row_id = 0
puzzle_id = 0
result = 0 while row_id < len(data):
assert(data[row_id] == "Grid {:0>2d}".format(puzzle_id + 1))
# print(time.strftime("%H:%M:%S ") + data[row_id])
row_id += 1 puzzle = []
for puzzle_row_id in range(dim):
puzzle.append([])
for col_id in range(dim):
puzzle[-1].append(int(data[row_id+puzzle_row_id][col_id]))
puzzle = solve(puzzle) result += int("{}{}{}".format(*puzzle[0]))
row_id += dim
puzzle_id += 1 print(result) t0 = time.time()
main()
t1 = time.time()
print "running time=",(t1-t0),"s"
#
# running time= 117.409999847 s
Project Euler 96:Su Doku 数独的更多相关文章
- Python练习题 039:Project Euler 011:网格中4个数字的最大乘积
本题来自 Project Euler 第11题:https://projecteuler.net/problem=11 # Project Euler: Problem 10: Largest pro ...
- [project euler] program 4
上一次接触 project euler 还是2011年的事情,做了前三道题,后来被第四题卡住了,前面几题的代码也没有保留下来. 今天试着暴力破解了一下,代码如下: (我大概是第 172,719 个解出 ...
- Python练习题 029:Project Euler 001:3和5的倍数
开始做 Project Euler 的练习题.网站上总共有565题,真是个大题库啊! # Project Euler, Problem 1: Multiples of 3 and 5 # If we ...
- Project Euler 9
题意:三个正整数a + b + c = 1000,a*a + b*b = c*c.求a*b*c. 解法:可以暴力枚举,但是也有数学方法. 首先,a,b,c中肯定有至少一个为偶数,否则和不可能为以上两个 ...
- Project Euler 44: Find the smallest pair of pentagonal numbers whose sum and difference is pentagonal.
In Problem 42 we dealt with triangular problems, in Problem 44 of Project Euler we deal with pentago ...
- project euler 169
project euler 169 题目链接:https://projecteuler.net/problem=169 参考题解:http://tieba.baidu.com/p/2738022069 ...
- 【Project Euler 8】Largest product in a series
题目要求是: The four adjacent digits in the 1000-digit number that have the greatest product are 9 × 9 × ...
- Project Euler 第一题效率分析
Project Euler: 欧拉计划是一系列挑战数学或者计算机编程问题,解决这些问题需要的不仅仅是数学功底. 启动这一项目的目的在于,为乐于探索的人提供一个钻研其他领域并且学习新知识的平台,将这一平 ...
- Python练习题 049:Project Euler 022:姓名分值
本题来自 Project Euler 第22题:https://projecteuler.net/problem=22 ''' Project Euler: Problem 22: Names sco ...
随机推荐
- js设计模式(3)---桥接模式
0.前言 看设计模式比较痛苦,一则是自己经验尚浅,不能体会到使用这些设计模式的益处:二则是不能很好把握使用这些设计模式的时机.所以这一部分看得断断续续,拖拖拉拉,为了了却这快心病,决定最近一口气看完几 ...
- Atan2
在三角函数中,两个参数的函数atan2是正切函数的 一个变种.对于任意不同时等于0的实参数x和y,atan2(y,x)所表达的意思是坐标原点为起点,指向(x,y)的射线在坐标平面上与x轴正方向之间 的 ...
- 一个好用的PHP验证码类
分享一个好用的php验证码类,包括调用示例. 说明: 如果不适用指定的字体,那么就用imagestring()函数,如果需要遇到指定的字体,就要用到imagettftext()函数.字体的位置在C盘下 ...
- openerp经典收藏 OpenERP库存管理的若干概念讲解(新增库存价值)(转载)
OpenERP库存管理的若干概念讲解(新增库存价值) 原文:http://shine-it.net/index.php/topic,2425.0/topicseen.html 一.复式库存(Doubl ...
- (二)使用log4net写入数据库自定义日志
1.配置项目环境 1.1 本文只显示需要修改配置的操作,初次引入log4net环境的请参考上文. 1.2 安装mysql-connector-net.msi环境,下载地址.并手动生成数据库日志信息表. ...
- MYSQL-给带特殊符号的数据库创建用户名
MYSQL-创建数据库及用户名: mysql> create database yoon;Query OK, 1 row affected (0.00 sec) mysql> grant ...
- java移位操作符
<<:左移操作符,右边补0,相当于乘二乘二... >>:右移操作符,左边补符号位(正数补0,负数补1),相当于除二除二... >>>:无符号右移,左边补0,相 ...
- Oracle 异常处理
1.什么是异常 在PL/SQL中的一个警告或错误的情形都可被称为异常.包括编译时错误(PLS)和运行时错误(ORA).一个异常通常包含一个错误代码和错误文本,分别指示异常的编号和具体错误信息. 异 ...
- C语言基础:数组和字符串
数组:数组的定义注意点 数组初始化正确写法: int args[5] = {1,23,32,4,5}; int args[5] = {12,23}; int args[5] = {[3]=23, [4 ...
- ADO.NET- 基础总结及实例介绍
最近闲暇时间写的一些小程序中,访问数据库比较多:下面主要介绍下ADO.NET方面知识,有不足之处,希望大神们不吝赐教: 提到ADO.NET,经常会和ASP.NET进行混淆,两者的区别很大,没有可比性, ...