數獨_約束求解_by C++ and Python

利用每一個空格的域空間進行約束求解,註釋應該夠了,直接貼代碼

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)




發佈了45 篇原創文章 · 獲贊 18 · 訪問量 7萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章