[英]Sudoku Solver brute force algorithm
仍在使用數獨解算器時,我再次遇到了一些麻煩。 我已經啟用了數獨求解器,但是每當我嘗試求解一個真正的“硬”數獨板時,由於堆棧溢出錯誤,我的求解器會告訴我沒有可能的解決方案。 是的,我知道這些主板確實有解決方案。
我正在使用蠻力算法-我從平方1開始(如果願意,可以從[0] [0]開始)並插入第一個合法值。 然后,我對下一個正方形進行遞歸調用,依此類推。 如果我的職能還沒有遍及整個董事會,並且發現沒有合法值,它將移至上一個平方並嘗試在該平方上增加該值。 如果失敗,它將進一步退回。 如果它以沒有可能的解決方案的平方結束,則退出。
我承認我的代碼不太漂亮,可能效率不高,但是請記住,我是一年級學生,努力做到最好。 我不介意評論如何實現我的代碼:)
對於沒有最終預定義數字的平方,這是求解器函數:
public void fillRemainderOfBoard(Square sender){
try {
while(true){
if(currentPos > boardDimension){
if(previous != null){
this.setNumrep(-1);
this.setCurrentPos(1);
previous.setCurrentPos(previous.getCurrentPos()+1);
previous.fillRemainderOfBoard(this);
return;
} else if(sender == this){
this.setCurrentPos(1);
} else {
break;
}
}
if((thisBox.hasNumber(currentPos)) || (thisRow.hasNumber(currentPos)) || (thisColumn.hasNumber(currentPos))){
currentPos++;
} else {
this.setNumrep(currentPos);
currentPos++;
break;
}
}
if(this != last){
next.setNumrep(-1);
next.fillRemainderOfBoard(this);
} else {
return;
}
} catch (StackOverflowError e){
return;
}
}
在我的代碼中,numrep值是正方形在板上表示的值。 currentPos變量是一個從1開始並遞增直到達到代表正方形的合法值的計數器。
對於具有預定義數字的正方形,以下是相同的功能:
public void fillRemainderOfBoard(Square sender){
if((sender.equals(this) || sender.equals(previous)) && this != last){
System.out.println(next);
next.fillRemainderOfBoard(this);
} else if (sender.equals(next) && this != first) {
previous.fillRemainderOfBoard(this);
} else {
System.out.println("No possible solutions for this board.");
}
}
現在,我的問題是,就像我說的那樣,該功能確實很好地解決了數獨問題。 簡單的。 像那些具有許多預定義數字且只有一個解決方案的數獨工具一樣,棘手的數獨只會使我的程序陷入堆棧溢出並告訴我沒有可能的解決方案。 我認為這表明我在內存管理方面缺少某些東西,或者程序在遞歸函數中調用了重復的對象,但是我不知道該如何解決。
任何幫助是極大的贊賞! 也可以隨意選擇我的代碼; 我還在學習(哦,我們不是一直嗎?)。
__ _ __ _ __ _ __ __ _ __ _ ____ 編輯 _ __ _ __ _ __ _ __ _ __ _
感謝Piotr提出了回溯的好主意,我重新編寫了代碼。 但是,我仍然無法解決任何數獨問題。 即使木板是空的,它也會到達第39號平方,然后一直返回false。 這是我當前的代碼:
public boolean fillInnRemainingOfBoard(Square sender){
if(this instanceof SquarePredef && next != null){
return next.fillInnRemainingOfBoard(this);
} else if (this instanceof SquarePredef && next == null){
return true;
}
if(this instanceof SquareNoPredef){
currentPos = 1;
if(next != null){
System.out.println(this.index);
for(; currentPos <= boardDimension; currentPos++){
if((thisBox.hasNumber(currentPos)) || (thisRow.hasNumber(currentPos)) || (thisColumn.hasNumber(currentPos))){
continue;
} else {
System.out.println("Box has " + currentPos + "? " + thisBox.hasNumber(currentPos));
this.setNumrep(currentPos);
System.out.println("Got here, square " + index + " i: " + numrep);
}
if(next != null && next.fillInnRemainingOfBoard(this)){
System.out.println("Returnerer true");
return true;
} else {
}
}
}
if(next == null){
return true;
}
}
System.out.println("Returning false. Square: " + index + " currentPos: " + currentPos);
return false;
}
我必須使事情復雜一點,因為我需要檢查當前對象是否是最后一個。 因此,額外的if測試。 哦,我使用boardDimension的原因是因為此數獨求解器將解決任何數獨-不僅是那些9 x 9的數獨:)
你能發現我的錯誤嗎? 任何幫助表示贊賞!
因此,您的問題出在這里:
previous.fillRemainderOfBoard(this);
和這里
next.fillRemainderOfBoard(this);
基本上,在堆棧上有太多的函數調用,因為您要多次前進和后退。 在找到答案之前,您並沒有真正從任何電話返回(否則會收到StackOverflowError :)。 與其通過使用遞歸函數來增加堆棧大小,不如思考如何使用循環來解決問題(在很多情況下,總是循環比在遞歸解決方案性能上要好得多)。 好的,因此您可以執行以下操作(偽代碼):
boolean fillRemainderOfBoard(Square sender){
if (num_defined_on_start) {
return next.fillRemainderOfBoard(this);
} else {
for (i = 1; i < 9; ++i) {
if (setting i a legal_move)
this.setCurrentPos(i);
else
continue;
if (next.fillRemainderOfBoard(this))
return true;
}
return false;
}
堆棧大小為〜81。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.