利用每一個空格的域空間進行約束求解,註釋應該夠了,直接貼代碼
C++:
#include <iostream>
#include <string>
#include <algorithm>
#include <vector>
#include <cstring>
using namespace std;
vector<int> CurDom[81];
int map[9][9];
vector< vector<int> > answer;
int num_of_blank;
int able_num[9];
int Assigned[81];
int counts = 0 ;
void init_CurDom(int map[9][9], int index )//index表示0~81某一位置索引,將該索引位置的行,列,方塊進行檢查,把可走的數字的域放入CurDom[index]的容器中
{
for ( int k = 0 ; k < 9 ; k ++ ) able_num[k] = k + 1;//先初始爲1~9,將行,列,方塊中出現的數字的索引置爲0,不爲零的即爲可走域
int i = index/9;
int j = index%9;
for ( int row = 0 ; row < 9 ; row ++ )
if ( map[row][j] != 0 ) able_num[ map[row][j] - 1 ] = 0;
for ( int col = 0 ; col < 9 ; col ++ )
if ( map[i][col] != 0 ) able_num[ map[i][col] - 1 ] = 0;
for ( int r = i/3*3 ; r < i/3*3 + 3 ; r ++ )
for ( int c = j/3*3 ; c < j/3*3 + 3 ; c ++ )
if ( map[r][c] != 0 ) able_num[ map[r][c] - 1 ] = 0;
for ( int k = 0 ; k < 9 ; k ++ )
if( able_num[k] != 0 ) CurDom[index].push_back( able_num[k] );
}
void init(int map[9][9],int & num)//初始化操作,num表示空格數目
{
for (int i = 0 ; i < 9 ; i ++ )
for ( int j = 0 ; j < 9 ; j ++ )
{
int index = i*9+j;
if( map[i][j] == 0 )
{
num ++;
init_CurDom( map, index );
}
else
Assigned[i*9+j]=1;//已經有值的位置置爲1
}
}
int PickAnUnassignedVariable()//找出可走的index,即爲訪問過的具有最少域空間的index值
{
int min_value = 10;
int min_index = 82;
for ( int i = 0 ; i < 81 ; i ++ )
{
if(Assigned[i] == 0 && CurDom[i].size() < min_value )
{
min_value = CurDom[i].size();
min_index = i;
}
}
return min_index;
}
bool have_d(int index , int d)//判斷CurDom[index]域空間中是否有d
{
for(int i = 0 ;i<CurDom[index].size();i++)
{
if(CurDom[index][i]==d) return true;
}
return false;
}
void remove_d(int index , int d)//將CurDom[index]域中的d刪除
{
vector<int> temp;
for(int j = 0 ;j<CurDom[index].size();j++)
if(CurDom[index][j] != d) temp.push_back(CurDom[index][j]);
CurDom[index].clear();
for(int i = 0 ; i < temp.size();i++) CurDom[index].push_back(temp[i]);
}
vector<int> temp_Assigned(int index,int d)//索引位置index中的d被選擇後,行,列,方塊中其他索引位置的域中有d值時將d刪除掉
{
int row = index/9;
int col = index%9;
vector<int> temp;
for(int i=0;i<9;i++)
{
int row_index = row*9+i;
if(Assigned[row_index] == 0)
{
if(have_d(row_index,d))
{
temp.push_back(row_index);
remove_d(row_index,d);
}
}
}
for(int i=0;i<9;i++)
{
int col_index = i*9+col;
if(Assigned[col_index] == 0)
{
if(have_d(col_index,d))
{
temp.push_back(col_index);
remove_d(col_index,d);
}
}
}
for(int i = row/3*3;i < row/3*3+3;i++)
for(int j = col/3*3;j<col/3*3+3;j++)
{
int square_index = i * 9 + j;
if(Assigned[square_index] == 0)
{
if(have_d(square_index,d))
{
temp.push_back(square_index);
remove_d(square_index,d);
}
}
}
return temp;
}
void Restore_CurDoms(vector<int> temp_Assigned_list, int d )//重新將被刪除d的索引位置的域空間加回d
{
for(int i=0;i<temp_Assigned_list.size();i++)
CurDom[temp_Assigned_list[i]].push_back(d);
}
bool GAC_Enforce() //判斷是否返回DWO
{
for(int i = 0 ; i < 81 ; i ++ )
{
if(Assigned[i] == 0 && CurDom[i].size() == 0 )
return false;
}
return true;
}
bool GAC(int level)//level爲空格數
{
if( level == 0 )//當空格數目減爲0時,則說明全部都找了一遍
{
return true;
}
int min_index = PickAnUnassignedVariable();//每次找到未被選擇的空格位置(最小域空間)
int row = min_index/9;
int col = min_index%9;
for(int k = 0 ;k < CurDom[min_index].size();k++ )//從該位置的域空間中選擇d
{
int d = CurDom[min_index][k];
vector<int> temp;
temp.push_back(row);
temp.push_back(col);
temp.push_back(d);
answer.push_back(temp);//先放入結果隊列
Assigned[min_index] = d;
vector<int> temp_Assigned_list = temp_Assigned(min_index,d);//list,裏面包含當前選擇d約束時受影響的位置鏈表
if(GAC_Enforce() == true)
{
if(GAC(level-1))//空格數-1
{
return true;
}
}
Restore_CurDoms(temp_Assigned_list,d);//域空間重新放回d
Assigned[min_index]=0;
answer.pop_back();
}
return false;
}
void print_map(int map[9][9])
{
for(int i=0;i<9;i++)
{
cout<<"[ ";
for(int j=0;j<9;j++)
{
cout<<map[i][j]<<" ";
if(j==2||j==5) cout<<"] [ ";
}
cout<<"]"<<endl;
if(i==2||i==5) cout<<endl;
}
}
void print_answer()
{
int step = 1;
for(int i = 0 ; i < answer.size() ; i ++ )
{
cout<<"step "<<step++<<": "<<"("<<answer[i][0]<<","<<answer[i][1]<<") ---> "<<answer[i][2]<<endl;
}
}
void solve(int map[9][9])
{
cout<<"原始數獨矩陣:"<<endl;
print_map(map);
int num = 0 ;
counts = 0 ;
init(map,num);
GAC(num);
print_answer();
for(int i=0;i<answer.size();i++)
{
map[answer[i][0]][answer[i][1]]=answer[i][2];
}
cout<<"GAC求解結果爲:"<<endl;
print_map(map);
cout<<"============================="<<endl;
answer.clear();
for(int i=0;i<81;i++)
CurDom[i].clear();
memset(Assigned,0,sizeof(Assigned));
}
int main()
{
int map1[9][9] = { //測試例子 1
{ 7, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 1, 6, 0, 9, 0, 0, 7, 0, 4 },
{ 0, 8, 0, 7, 0, 0, 0, 0, 0 },
{ 0, 0, 5, 0, 0, 9, 0, 3, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 2, 0 },
{ 0, 1, 9, 0, 8, 0, 5, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 2, 0, 1 },
{ 5, 3, 0, 1, 0, 0, 9, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 8, 0 }
};
int map2[9][9] = { //測試例子 2
{ 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 1, 0, 0, 6, 4, 0, 0 },
{ 9, 0, 0, 0, 3, 0, 0, 0, 0 },
{ 0, 0, 0, 1, 0, 0, 8, 0, 0 },
{ 7, 8, 0, 5, 0, 0, 0, 0, 0 },
{ 3, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 6, 3 },
{ 0, 0, 0, 0, 0, 0, 0, 7, 0 },
{ 0, 0, 2, 8, 0, 9, 0, 0, 0 }
};
int map3[9][9] = { //測試例子 3
{ 0, 0, 0, 0, 0, 2, 0, 0, 8 },
{ 6, 0, 3, 0, 1, 0, 0, 0, 0 },
{ 0, 0, 8, 0, 0, 3, 0, 0, 5 },
{ 8, 6, 0, 9, 2, 0, 0, 5, 3 },
{ 4, 0, 0, 3, 0, 0, 0, 1, 0 },
{ 5, 0, 0, 0, 8, 0, 0, 4, 0 },
{ 0, 4, 0, 0, 0, 7, 2, 0, 0 },
{ 0, 2, 0, 0, 0, 9, 0, 0, 0 },
{ 0, 0, 0, 2, 0, 0, 5, 3, 0 }
};
cout<<"求解第一個樣例:"<<endl;
solve(map1);
cout<<"求解第二個樣例:"<<endl;
solve(map2);
cout<<"求解第三個樣例:"<<endl;
solve(map3);
return 0 ;
}
Python:
__author = 'Hmx'
map1 = [
[7, 0, 0, 0, 0, 0, 0, 0, 0],
[1, 6, 0, 9, 0, 0, 7, 0, 4],
[0, 8, 0, 7, 0, 0, 0, 0, 0],
[0, 0, 5, 0, 0, 9, 0, 3, 0],
[0, 0, 0, 0, 0, 0, 0, 2, 0],
[0, 1, 9, 0, 8, 0, 5, 0, 0],
[0, 0, 0, 0, 0, 0, 2, 0, 1],
[5, 3, 0, 1, 0, 0, 9, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 8, 0]]
map2 = [
[0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 1, 0, 0, 6, 4, 0, 0],
[9, 0, 0, 0, 3, 0, 0, 0, 0],
[0, 0, 0, 1, 0, 0, 8, 0, 0],
[7, 8, 0, 5, 0, 0, 0, 0, 0],
[3, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 6, 3],
[0, 0, 0, 0, 0, 0, 0, 7, 0],
[0, 0, 2, 8, 0, 9, 0, 0, 0]]
map3 = [
[0, 0, 0, 0, 0, 2, 0, 0, 8],
[6, 0, 3, 0, 1, 0, 0, 0, 0],
[0, 0, 8, 0, 0, 3, 0, 0, 5],
[8, 6, 0, 9, 2, 0, 0, 5, 3],
[4, 0, 0, 3, 0, 0, 0, 1, 0],
[5, 0, 0, 0, 8, 0, 0, 4, 0],
[0, 4, 0, 0, 0, 7, 2, 0, 0],
[0, 2, 0, 0, 0, 9, 0, 0, 0],
[0, 0, 0, 2, 0, 0, 5, 3, 0]]
def init_CurDom(map,index):#index表示0~81某一位置索引,將該索引位置的行,列,方塊進行檢查,把可走的數字的域放入CurDom[index]的容器中
global CurDom
able_num = []
temp = []
row = index//9
col = index%9
for i in range(10):
able_num.append(1)#先初始爲1,將行,列,方塊中出現的數字的索引置爲0,不爲零的即爲可走域
for i in range(9):
if(map[i][col]):
able_num[map[i][col]] = 0
for i in range(9):
if(map[row][i]):
able_num[map[row][i]] = 0
row1 = row//3*3
row2 = row1+3
col1 = col//3*3
col2 = col1+3
for i in range(row1,row2):
for j in range(col1,col2):
if(map[i][j]):
able_num[map[i][j]] = 0
for i in range(9):
if(able_num[i+1]):
temp.append(i+1)
CurDom.append(temp)
def init(map):#初始化操作,num表示空格數目
global Assigned
global num
global CurDom
for i in range(81):
Assigned.append(0)
for index in range(81):
i = index//9
j = index%9
if(map[i][j]==0):
num = num + 1
init_CurDom(map,index)
else:
Assigned[index] = 1#已經有值的位置置爲1
CurDom.append([])
def PickAnUnassignedVariable():#//找出可走的index,即爲訪問過的具有最少域空間的index值
global CurDom
global Assigned
min_value = 10
min_index = 82
for i in range(81):
if(Assigned[i] == 0):
if(len(CurDom[i])<min_value):
min_value = len(CurDom[i])
min_index = i
return min_index
def temp_Assigned(index,d):#索引位置index中的d被選擇後,行,列,方塊中其他索引位置的域中有d值時將d刪除掉
global CurDom
global Assigned
row = index//9
col = index%9
temp = []
for i in range(9):
row_index = row*9+i
if(Assigned[row_index]==0):
if d in CurDom[row_index]:
temp.append(row_index)
CurDom[row_index].remove(d)
for i in range(9):
col_index = i*9 + col
if(Assigned[col_index]==0):
if d in CurDom[col_index]:
temp.append(col_index)
CurDom[col_index].remove(d)
row1 = row//3*3
row2 = row1+3
col1 = col//3*3
col2 = col1+3
for i in range(row1,row2):
for j in range(col1,col2):
square_index = i*9+j
if(Assigned[square_index]==0):
if d in CurDom[square_index]:
temp.append(square_index)
CurDom[square_index].remove(d)
return temp
def Restore_CurDom(store_list,d):#重新將被刪除d的索引位置的域空間加回d
global CurDom
for i in store_list:
CurDom[i].append(d)
def GAC_Enfore():#判斷是否返回DWO
global Assigned
global CurDom
for i in range(81):
if(Assigned[i]==0):
if(len(CurDom[i])==0):
return False
return True
def GAC(level):#level爲空格數
global CurDom
global Assigned
global answer
global count
if level is 0:#當空格數目減爲0時,則說明全部都找了一遍
return True
min_index = PickAnUnassignedVariable()#每次找到未被選擇的空格位置(最小域空間)
row = min_index//9
col = min_index%9
for d in CurDom[min_index]:#從該位置的域空間中選擇d
answer.append([row,col,d])#先放入結果隊列
Assigned[min_index] = d
temp_Assigned_list = temp_Assigned(min_index,d)#list,裏面包含當前選擇d約束時受影響的位置鏈表
if(GAC_Enfore):
if(GAC(level-1)):#空格數-1
return True
Restore_CurDom(temp_Assigned_list,d)#域空間重新放回d
Assigned[min_index] = 0
answer.remove([row,col,d])
return False
def print_map(map):
for i in range(9):
temp = ""
temp = temp + "[ "
for j in range(9):
temp = temp + str(map[i][j]) + " "
if(j==2 or j==5):
temp = temp + "] [ "
temp = temp + "]\n"
if(i==2 or i==5):
temp = temp + "\n"
print(temp)
def print_answer():
global answer
step = 0
for data in answer:
step = step + 1
print("step ",step,": (",data[0],",",data[1],") ---> ",data[2])
def solve(map):
global num
global answer
global CurDom
global Assigned
global count
count = 0
num = 0
answer = []
Assigned = []
CurDom = []
print("原始數獨矩陣:\n")
print_map(map)
init(map)
GAC(num)
print_answer()
for data in answer:
map[data[0]][data[1]] = data[2]
print("GAC求解結果爲:\n")
print_map(map)
print('='*31)
if __name__ == '__main__':
print("求解第一個樣例\n")
solve(map1)
print("求解第二個樣例\n")
solve(map2)
print("求解第三個樣例\n")
solve(map3)