數(shù)據(jù)結(jié)構(gòu)算法:數(shù)獨(dú)求解算法

字號(hào):

在上海乘坐地鐵的朋友都知道,上海地鐵站免費(fèi)贈(zèng)閱的時(shí)代報(bào)上,經(jīng)常會(huì)刊登有數(shù)獨(dú)這個(gè)益智游戲。如果用紙和筆人工去算的話(huà),恐怕你要花上老半天功夫了,有時(shí)候還不一定能解出來(lái),心中一定很郁悶吧?網(wǎng)上也有一些數(shù)獨(dú)游戲的求解計(jì)算器,不過(guò)我想與其直接拿來(lái)主義,還不如自己研究編一個(gè)呢!所以,花了大概有一個(gè)多月的時(shí)間來(lái)編寫(xiě)了這樣一個(gè)數(shù)獨(dú)求解軟件。由于不是利用所謂的窮舉算法,所以如果數(shù)獨(dú)游戲非解的話(huà),它就只提供最先找到的那個(gè)解。不過(guò),請(qǐng)放心,肯定是正確的!下面我就來(lái)詳述一下這個(gè)算法的精要。
    1、定義一個(gè)類(lèi),代表數(shù)獨(dú)游戲中的每一個(gè)數(shù)。它有如下屬性: #region 屬性
    ///
    /// 數(shù)值
    ///
    public int Num
    {
    set
    {
    if (UnFilled)
    {
    _num = value;
    _unfilled = false;
    Choices.Clear();
    SetNumEvent(this);
    }
    }
    get { return _num; }
    }
    ///
    /// 行坐標(biāo)
    ///
    public int Xpos
    {
    set { _x = value; }
    get { return _x; }
    }
    ///
    /// 列坐標(biāo)
    ///
    public int Ypos
    {
    set { _y = value; }
    get { return _y; }
    }
    ///
    /// 是否已填充的標(biāo)記
    ///
    public bool UnFilled
    {
    get { return _unfilled; }
    }
    ///
    /// 候選數(shù)列表
    ///
    public List Choices
    {
    set { _choices = value; }
    get { return _choices; }
    }
    #endregion
    2、在求解的主類(lèi)里,根據(jù)游戲的規(guī)則,設(shè)計(jì)這樣一套算法。當(dāng)某一個(gè)數(shù)值被設(shè)定以后,與它同行或同列的以及在同一個(gè)九宮里的數(shù)的候選數(shù)列里都要去掉這個(gè)數(shù)本身。數(shù)獨(dú)游戲中出現(xiàn)的數(shù)為已知數(shù),需要我們填補(bǔ)的則是未知數(shù)。未知數(shù)需要我們?nèi)ピ嚱?,不過(guò)在試解之前先要備份初始化以后的數(shù)組矩陣,以備在前一次試解失敗以后進(jìn)行恢復(fù)再進(jìn)行下一次試解,直到試解成功為止。
    3、算法本身看上去不是太復(fù)雜,但是涉及到一個(gè)遍歷和回滾的問(wèn)題。所以,在編程的時(shí)候還是要注意一下的。
    下面我就來(lái)簡(jiǎn)單介紹一下這個(gè)數(shù)獨(dú)求解軟件的操作和使用方法:
    軟件總體來(lái)說(shuō)還是操作比較簡(jiǎn)單的,但是由于當(dāng)時(shí)編寫(xiě)的時(shí)候只是想給自己用的,所以并沒(méi)有設(shè)計(jì)菜單和幫助文檔。用戶(hù)在輸入初始數(shù)據(jù)的時(shí)候可以用上下左右方向鍵或者ASDF來(lái)進(jìn)行跳格。如果數(shù)錯(cuò)了,在按確定按鈕以前可以按Back Space或Delete鍵進(jìn)行修改;一旦按了確定按鈕,就只得按F5清空后重新輸入了。
    軟件下載地址:http://download.csdn.net/source/512093
    源碼下載地址:http://download.csdn.net/source/512102