happytc
发表于 2012-4-17 09:21:30
回复 31# pusofalse
呵,这种方法,本质上跟我在30#提的方法其实是一样的。
只是这样产生的数独矩阵作成的九宫图,规律性太强了,解了一个,后的就很容易了。
所以我说很是ws,哈……
魔导
发表于 2012-4-17 09:55:55
小弟小学文化,来看看热闹{:face (394):}
seniors
发表于 2012-4-17 10:11:49
看不懂啊,看不懂,慢慢领悟
user3000
发表于 2012-4-17 16:15:22
本帖最后由 user3000 于 2012-4-17 16:48 编辑
一一推翻原来的思路, 看来要好好研究三笑的代码才行了!
user3000
发表于 2012-4-17 19:24:50
脑子不够用了!
静下心来, 看了看P侠的代码, 忽然才发现, 这世界其实很'小'!
whitehead
发表于 2012-4-17 21:19:33
写出解所有数独问题的算法应该很难吧
zch11230
发表于 2012-4-18 01:03:34
P大的太精彩了佩服
happytc
发表于 2012-4-18 05:52:01
写出解所有数独问题的算法应该很难吧
whitehead 发表于 2012-4-17 21:19 http://www.autoitx.com/images/common/back.gif
我在29楼不是已经给出来了嘛
你把所给的数独数组里多改几个非0数字为0,就可以看到可以得到多个答案了。
理论上完全可以得到所有数独的解,只是计算时间就是天文数字了。
不过数学家已经从理论上证明的有多少种数独矩阵了。
其实另外一个问题更有趣:如何产生:给出尽量少的数字情况下的九宫图是唯一解?
3mile
发表于 2012-4-18 09:43:57
回复 39# happytc
正如happytc兄所说,29楼的代码如果是给出全0的数,猜数独的话,是可以出全排列的.
这也就解释了为何如happytc兄所举的例子中Local $array = [, _
, _
, _
, _
, _
, _
, _
, _
]
第中的6挖去我的代码会出现死循环的结果.
happytc兄的代码是猜数,我的代码是去除不可能的数,happytc兄的代码设计想法非常先进,让人非常佩服.
虽然如此,但还是给出我在6楼代码中的修正代码,仅仅作为论坛留档,避免本地硬盘中文件管理混乱.
#include <array.au3>
$time = TimerInit()
Global $flag_W = 1
Local $k = "1234567890"
;~ Local $array = [,,,,,,,,]
Local $array = [, _
, _
, _
, _
, _
, _
, _
, _
]
$abc = sudoku($array)
_ArrayDisplay($abc, TimerDiff($time))
Func sudoku($array)
Local $str
For $i = 0 To 8;初始化
For $n = 0 To 8
$str &= $array[$i][$n] & "|"
Next
$str_1 = StringRegExpReplace($k, $str, '')
$str = ""
For $n = 0 To 8
If $array[$i][$n] = 0 Then $array[$i][$n] = $str_1
Next
$str_1 = ""
Next
;~ _ArrayDisplay($array)
While 1
;去除行重复
For $i = 0 To 8
Local $str = '', $aabb = ""
For $n = 0 To 8
If StringLen($array[$i][$n]) = 1 Then
$str &= $array[$i][$n] & "|"
EndIf
$aabb &= $array[$i][$n] & "|"
Next
For $n = 0 To 8
If StringLen($array[$i][$n]) > 1 Then
$array[$i][$n] = StringRegExpReplace($array[$i][$n], $str, '')
EndIf
Next
Local $fl =
For $o = 1 To 9
$min = StringRegExp($aabb, $o, 3)
If UBound($min) = 1 Then
_ArrayAdd($fl, $o)
EndIf
Next
For $n = 0 To 8
For $c = 1 To UBound($fl) - 1
If StringInStr($array[$i][$n], $fl[$c]) Then $array[$i][$n] = $fl[$c]
Next
Next
Next
;以下去除列重复
For $i = 0 To 8
Local $str = ''
For $n = 0 To 8
If StringLen($array[$n][$i]) = 1 Then
$str &= $array[$n][$i] & "|"
EndIf
Next
For $n = 0 To 8
If StringLen($array[$n][$i]) > 1 Then
$array[$n][$i] = StringRegExpReplace($array[$n][$i], $str, '')
EndIf
Next
Next
;去除九宫重复
For $i = 0 To 8 Step 3
For $n = 0 To 8 Step 3
Local $temp, $sp = '', $aabb = ""
For $a = 0 To 2
For $b = 0 To 2
If StringLen($array[$a + $i][$b + $n]) = 1 Then $sp &= $array[$a + $i][$b + $n]
Next
Next
For $a = 0 To 2
For $b = 0 To 2
If StringLen($array[$a + $i][$b + $n]) > 1 Then $array[$a + $i][$b + $n] = StringRegExpReplace($array[$a + $i][$b + $n], '[' & $sp & ']', '')
$aabb &= $array[$a + $i][$b + $n] & "|"
Next
Next
Local $fl =
For $o = 1 To 9
$min = StringRegExp($aabb, $o, 3)
If UBound($min) = 1 Then
_ArrayAdd($fl, $o)
EndIf
Next
For $a = 0 To 2
For $b = 0 To 2
For $c = 1 To UBound($fl) - 1
If StringInStr($array[$a + $i][$b + $n], $fl[$c]) Then $array[$a + $i][$b + $n] = $fl[$c]
Next
Next
Next
Next
Next
Local $flag = 0
For $i = 0 To 8
For $n = 0 To 8
If StringLen($array[$i][$n]) > 1 Then $flag = 1
Next
Next
;~ _ArrayDisplay($array)
If $flag = 0 Then ExitLoop
$flag_W += 1
If $flag_W > 10 Then
MsgBox(0,0,"不止一种解,或许条件不完整!")
ExitLoop
endif
WEnd
Return $array
EndFunc ;==>sudoku
whitehead
发表于 2012-4-18 20:32:49
确实,无论如何只有有限多种可能,理论上计算机是能够求出解的。
kenan
发表于 2012-4-19 04:29:10
睡不着,把这道题做了
同学说用回溯法就可以解决。我一开始怎么就没想到这个呢,还以为是要找出什么规律,每个数字都可以算出来的
c++代码,写得应该很清晰了,au3就不写了#include <iostream>
using namespace std;
bool CanPut(int *a [],int n,int k){
int row=k/9;
int col=k%9;
int i;
for(i=0;i<9;i++){
if(a==n) return false;
if(a==n) return false;
}
row=row/3*3;
col=col/3*3;
for(i=0;i<3;i++)
for(int j=0;j<3;j++)
if(a==n) return false;
return true;
}
void BackTrack(int *a [],int k){
if(k==81) {
for(int i = 0; i < 9; ++i){
for(int j = 0; j < 9; ++j){
cout<< a<<" ";
}
cout<<endl;
}
return;
}
int row=k/9;
int col=k%9;
int i;
if(a==0){
for(i=1;i<=9;i++){
if(CanPut(a,i,k)){
a=i;
BackTrack(a,k+1);
a=0;
}
}
if(a==0){
return;
}
}
BackTrack(a,k+1);
}
int main(){
int **a = new int*;
for(int i = 0; i < 9; ++i){
a = new int;
for(int j = 0; j < 9; ++j){
cin >> a;
}
}
cout<<endl;
BackTrack(a,0);
return 0;
}
/*
0 6 1 0 3 0 0 2 0
0 5 0 0 0 8 1 0 7
0 0 0 0 0 7 0 3 4
0 0 9 0 0 6 0 7 8
0 0 3 2 0 9 5 0 0
5 7 0 3 0 0 9 0 0
1 9 0 7 0 0 0 0 0
8 0 2 4 0 0 0 6 0
0 4 0 0 1 0 2 5 0
*/
kenan
发表于 2012-4-19 04:53:36
本帖最后由 kenan 于 2012-4-19 14:06 编辑
大清早起来,花上点时间做下这个题
三笑,你的代码可能有问题的或效率低,当把数字多挖几个出去,就 ...
happytc 发表于 2012-4-17 06:25 http://www.autoitx.com/images/common/back.gif
都是回溯法,感觉你写的复杂一点,扫了几眼,没能完全读懂
其实思路很简单,按顺序一个数字一个数字的填,比如,填第一个数字,从1-9中,把1填进去发现能满足要求,那么继续填第二个数字,从1-9中,填1不行,填2不行,继续填3,行了,填第三个数字,从1-9,发现1-9都不能满足要求,那么就回退,重填第二个数字,3不能填,那么填4填5看行不行,如果行了,那就继续填第三个数字。。。。以此类推
MicroBlue
发表于 2012-4-19 18:28:51
看看3mail的答案是什么!
whitehead
发表于 2012-4-20 23:21:07
回复 42# kenan
这就是计算机求解与人脑求解的不同之处。
人脑能用的方法电脑用不了,反之大体一样