1. 程式人生 > >數獨求解(c語言以及python)

數獨求解(c語言以及python)

/*
 ============================================================================
 Name        : sudoku.c
 Author      : Joey
 Version     :
 Copyright   : UESTC
 Description : Try to solve sudoku puzzle.
 1.0   2010年10月27日20:28:13  Create
 1.1    2010-11-9 19:03:22 modify
輸入引數:儲存數獨棋盤格局的檔名
        檔案的資料是9*9的矩陣,每個數的取值範圍為0-9
        0表示該位置對應棋盤上的資料位空
        1-9代表該位置對應的數
    如果不提供輸入引數,程式會以互動式的方式請求使用者指定一個檔名。

 ============================================================================
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//#include <time.h>

//#define _DEBUG  /*除錯開關*/

#define MAX_FILE_NAME_LEN 30    /*檔名字串最大長度*/
#define BOARD_SIZE 9    /*棋盤大小*/
#define BLOCK_SIZE 3    /*每塊區域大小*/

#define VALID_MASK 0x03FE   /*倒數第2位至倒數10位為有效標誌位*/

/**
 * 這些巨集定義用於將標誌位置位或者清除
 */
#define setblockbit(rowidx,colidx,a) (blockbits[rowidx/3][colidx/3] |= 1<<a)
#define clearblockbit(rowidx, colidx, a) (blockbits[rowidx/3][colidx/3] &= ~(1<<a))
#define testblockbit(rowidx, colidx, a) (blockbits[rowidx/3][colidx/3] & (1<<a) & VALID_MASK)


#define setrowbit(rowidx,a) (rowbits[rowidx] |= 1<<a)
#define clearrowbit(rowidx,a) (rowbits[rowidx] &= ~(1<<a))
#define testrowbit(rowidx, a) (rowbits[rowidx] & (1<<a) &VALID_MASK)

#define setcolumnbit(colidx,a) (columnbits[colidx] |= 1<<a)
#define clearcolumnbit(colidx,a) (columnbits[colidx] &= ~(1<<a))
#define testcolumnbit(colidx,a) (columnbits[colidx] & (1<<a) & VALID_MASK)

/**
 * 位置型別
 */
typedef struct Coodinate_T{
        int row;
        int column;
}Coordinate;

typedef struct Stkelemnt_T{
        int idx;
        int number;
}Stkelement;


int board[BOARD_SIZE][BOARD_SIZE];/*儲存棋盤資料*/

unsigned short blockbits[BLOCK_SIZE][BLOCK_SIZE];/*儲存9個3*3方塊的資料狀態*/
unsigned short rowbits[BOARD_SIZE];     /*儲存每一行資料狀態*/
unsigned short columnbits[BOARD_SIZE];  /*儲存每一列的資料狀態*/
Coordinate blanklist[BOARD_SIZE*BOARD_SIZE]; /*儲存了待填寫等方格位置*/
int blanknum = 0;   /*待填寫方格總個數*/


/************************************/
 /* Internal struct for DFS algorithm*/
Stkelement stk[300];
int top = 0;
/***********************************/

void trysolve(FILE *fp);
int loadAndCheckInitBoard(FILE *fp);
int searchAns(int row, int column, int from);
int solve();
void pushstk(int blankidx, int num);
Stkelement popstk();
void outputresult();
#ifdef _DEBUG
void printstk();
#endif

/**
 *程式入口,第一個執行引數為輸入檔案檔名,若不存在,從控制檯中互動獲取檔名
 */
int main(int argc, char** argv) {
    char filename[MAX_FILE_NAME_LEN];
    FILE *fp = NULL;
    if (argc <= 1){
        printf("input file name:");
        scanf("%s",filename);
    }else{
        strcpy(filename, argv[1]);
    }
    fp = fopen(filename,"r");
    if (fp == NULL){
        fprintf(stderr,"Error occurred when open file %s", filename);
        exit(EXIT_FAILURE);
    }
    trysolve(fp);
    fclose(fp);
	return EXIT_SUCCESS;
}

/**
 * 輸入:
 *      row:格子的行
 *      column:格子的列
 *      from:從該數開始遞增查詢
 * 輸出:返回值為
 *              0:未找到
 *              1-9:找到的可行解
 */
int searchAns(int row, int column, int from){
    int number = from;
    if (number > 9 || number < 1){    //起始值過大或過小
        return 0;
    }
    while (number <= 9){
        if (testblockbit(row, column, number)==0
                && testrowbit(row, number)==0
                && testcolumnbit(column, number)==0){
            return number;
        }else
            number++;
    }
    return 0;   /*未找到*/

}

/**
 * 從fp指向的檔案中讀取初始棋盤,嘗試解決數獨問題
 */
void trysolve(FILE *fp){
    int rt = loadAndCheckInitBoard(fp);
    if (1 == rt){
        printf("Initial board isn't correct!\n");
    }else if (2 == rt ){
        printf("Invalid data was contented in the file!\n");
    }else if (3== rt){
        printf("資料不完整\n");
    }else{
        printf("Load board successfully, try to solve...\n");
        if (solve() == 0){
            printf("Success, result:\n");
            outputresult();
        }else{
            printf("The puzzle can't be solved\n");
        }
    }
    return;

}

/**
 * 載入初始棋盤並對數獨棋盤的可解性做初步檢查,棋盤有效資料為0-9,大小為9*9
 * fp:
 *      已開啟的檔案指標
 * 返回值:
 *      0:成功讀取9*9棋盤
 *      1:初始棋盤不合規則
 *      2:檔案中包含無效資料
 *      3:資料不完整
 */
int loadAndCheckInitBoard(FILE *fp){
    int a;
    int idx = 0;
    int rowidx = 0;
    int columnidx = 0;
    Coordinate cood;
    while(fscanf(fp, "%d", &a) != EOF){
        rowidx = idx / 9;       /*行數*/
        columnidx = idx % 9;    /*列數*/
        if (a >= 1 && a <= 9){  /*如果是已填格子*/
            if (testblockbit(rowidx,columnidx,a) == 0
                    && testcolumnbit(columnidx,a) == 0
                    && testrowbit(rowidx, a) == 0){
                setblockbit(rowidx, columnidx, a);
                setrowbit(rowidx, a);
                setcolumnbit(columnidx, a);
            }else{
                return 1;   /*初始棋盤本身有錯*/
            }
        }else if (a == 0){  /*如果是待填格子,記錄下待填格子的座標*/
            cood.row = rowidx;
            cood.column = columnidx;
            blanklist[blanknum++] = cood;
        }else{
            return 2;   /*發現無效資料*/
        }
        board[rowidx][columnidx] = a;
        idx++;
    }
    /*資料不夠,格式錯誤*/
    if (idx != BOARD_SIZE * BOARD_SIZE){
        return 3;
    }
    return 0;   /*載入成功*/
}

/**
 *  遞迴求解數獨問題,呼叫前初始資料已被正確讀取,
 *  返回值:
 *      0:找到一個可行解
 *      1:未找到可行解
 */
int solve(){
    int fillidx = 0;    /*fill index in blanklist*/
    int ans = 0;
    Stkelement curcell;

    pushstk(fillidx, ans);  /*初始入棧的值*/
    while (top != 0){   /*棧不為空*/
#ifdef _DEBUG
        printstk();
#endif
        curcell = popstk();
        ans = curcell.number;
        fillidx = curcell.idx;

        ans = searchAns(blanklist[fillidx].row, blanklist[fillidx].column,
                ans+1);
        while(ans != 0){
            pushstk(fillidx, ans);
#ifdef _DEBUG
            printstk();
#endif
            if (fillidx == blanknum-1){
                return 0;   /*找到了一個可行解*/
            }
            fillidx++;
            ans = searchAns(blanklist[fillidx].row, blanklist[fillidx].column,
                1);
        }
    }
     return 1;  /*無解*/
}

/**
 * 將blankidx對應的座標壓入棧中,並根據該位置上的數字將相應的bit置位
 */
void pushstk(int blankidx, int num){
    /*set bits*/
    setblockbit(blanklist[blankidx].row, blanklist[blankidx].column, num);
    setrowbit(blanklist[blankidx].row, num);
    setcolumnbit(blanklist[blankidx].column, num);

    /*push into stack*/
    Stkelement ele = {blankidx, num};
    stk[top++] = ele;
    return ;

}

/**
 * 彈出棧頂的元素,並將該元素對應的bit清楚
 */
Stkelement popstk(){
    Stkelement ele = stk[--top];
    /*clear bits*/
    clearblockbit(blanklist[ele.idx].row, blanklist[ele.idx].column, ele.number);
    clearrowbit(blanklist[ele.idx].row, ele.number);
    clearcolumnbit(blanklist[ele.idx].column, ele.number);
    /**/
    return ele;
}


#ifdef _DEBUG
void printstk(){
    int i = top-1;
    printf("***********Stack trace************\n");
    for (;i >= 0; i--){
        printf("%dth row:%d column:%d number:%d\n",
                i, blanklist[stk[i].idx].row, blanklist[stk[i].idx].column,
                stk[i].number);
    }
    printf("**********************************\n");
    fflush(stdout);
}
#endif

/**
 * 輸出結果至標準輸出裝置
 */
void outputresult(){
    int r,c;
    int i = 0;
    for (;i < top; i++){
        board[blanklist[stk[i].idx].row][blanklist[stk[i].idx].column]
                                         = stk[i].number;
    }
    for (r =  0; r < BOARD_SIZE; r++){
        for (c = 0; c < BOARD_SIZE; c++){
            printf("%d ",board[r][c]);
        }
        printf("\n");
    }
    fflush(stdout);
}

Python版的

#coding=utf-8
'''
Created on 2011-11-29
解決8皇后問題
廣搜演算法
@author: Joey
'''
import copy

def solve():
    queue = []
    for i in range(8):
        queue.append([(0,i)])
    results = []
    max = 0
    while len(queue) > 0:
        poslist = queue.pop(0)
        lastrow = poslist[-1][0]
        assert lastrow < 7
        for col in range(0,8):
            if islegal((lastrow+1,col), poslist):
                poslstcpy = copy.deepcopy(poslist)
                poslstcpy.append((lastrow+1,col))
                if len(poslstcpy) == 8:
                    results.append(poslstcpy)
                else:
                    queue.append(poslstcpy)
        if len(queue) > max: max = len(queue)

    print max         
    print len(results)
    for item in results:
        printresul(item)

def islegal(pos, poslist):
    for xpos in poslist:
        if xpos[0] == pos[0] or xpos[1] == pos[1] \
        or abs(xpos[0]-pos[0]) == abs(xpos[1]-pos[1]):
            return False  
    return True

def printresul(poslist):
    for row in range(8):
        for col in range(8):
            if (row,col) in poslist:
                print 'o',
            else:
                print '.',
        print ' '
    print '--------'
solve()


相關推薦

求解c語言以及python

/* ============================================================================ Name : sudoku.c Author : Joey Version

遞迴求解C語言

遞迴求解數獨(C語言) 本程式採用c語言編寫,作用是獲得一個數獨的解。 經測試,計算普通數獨時間花費不大於0.02秒。 計算“世界最難數獨”時間花費約為0.05秒。 計算效率中等,有待提高。 程式核心函式為place(),作用為遞迴設定下一個位置的值。

優先隊列堆) -據結構C語言實現

++ eem enter ext lock 二次 arr 快速 left 數據結構與算法分析 優先隊列 模型 Insert(插入) == Enqueue(入隊) DeleteMin(刪除最小者) == Dequeue(出隊) 基本實現 簡單鏈表:在表頭插入,並遍歷

計算1~100之間,能被3整除但是不能被7整除的的和C語言

#include<stdio.h> int main(agrc *agrv) { int n,i; int sum=0; scanf("%d",&n); for(i=1;i<=n;i++){ if(i%3==0&&i%7!=0){ sum+=i; &

迴文—簡單方法C語言

迴文數即正反讀都是相同的數,如151、12321等,但不要忘了,個位數與0也是迴文數,雖然這不影響我們程式碼。 題目要求:輸入n組資料,每組資料判斷是否為迴文數,是的話輸出各位數和,不是輸出no; 既然正反都是相同,許多同學用了兩個陣列進行正反比對,但我認為我的方法更為簡易。程式碼如下。

LeetCode 18. 四之和 4SumC語言

題目描述: 給定一個包含 n 個整數的陣列 nums 和一個目標值 target,判斷 nums 中是否存在四個元素 a,b,c 和 d ,使得 a + b + c + d 的值與 target 相等?找出所有滿足條件且不重複的四元組。 注意: 答案中不可以包含重複的四元組。

LeetCode 9. 迴文 Palindrome NumberC語言

題目描述: 判斷一個整數是否是迴文數。迴文數是指正序(從左向右)和倒序(從右向左)讀都是一樣的整數。 示例 1: 輸入: 121 輸出: true 示例 2: 輸入: -121 輸出: false 解釋: 從左向右讀, 為 -121 。 從右向左

LeetCode 15. 三之和 3SumC語言

題目描述: 給定一個包含 n 個整數的陣列 nums,判斷 nums 中是否存在三個元素 a,b,c ,使得 a + b + c = 0 ?找出所有滿足條件且不重複的三元組。 注意:答案中不可以包含重複的三元組。 例如, 給定陣列 nums = [-1, 0, 1, 2,

迴文的判斷C語言實現

http://blog.sina.com.cn/s/blog_5072a15d0100msdb.html 無名小浪 https://zhidao.baidu.com/question/548255538.html zhuhuaizhong 原理: 任何一個數除以10的餘

一箇中興的面試題,輸入兩個數n和m,從數列1,2,3……n中隨意取幾個數,使其和等於m,要求將其中所有組合列出來程式設計求解c語言遞迴函式分解法

原題目:輸入兩個數n和m,從數列1,2,3……n中隨意取幾個數,使其和等於m,要求將其中所有組合列出來程式設計求解 c語言解法分析:            先判定n和m的大小,如果m小於n,則只需從1,2……m之間找出和為m的組合即可,如果m大於n,則需要判斷1~n的和是否

之和問題C語言解法

給定一個整數陣列和一個目標值,找出陣列中和為目標值的兩個數。你可以假設每個輸入只對應一種答案,且同樣的元素不能被重複利用。算例:給定 nums = [2, 7, 11, 15], target = 9

據結構C語言

info bsp cpp work spa clu 順序 9.png error 首先,學會用Vistual C++創建一個順序表,以及對順序表的基本操作。 (1)新建一個工程 Win30Application (2)新建SeqList.h (3)新建SeqList.

漢諾塔的故事C語言——遞歸

code log 圓盤 印度 return 16px move class baidu 漢諾塔:   漢諾塔(又稱河內塔)問題是源於印度一個古老傳說的益智玩具。大梵天創造世界的時候做了三根金剛石柱子,在一根柱子上從下往上按照大小順序摞著64片黃金圓盤。大梵天命令婆羅門把圓盤

資料結構---棧C語言陣列實現

https://blog.csdn.net/morixinguan/article/details/51374184 資料結構---棧(C語言陣列實現)   棧的全名稱為堆疊,棧其實就是與佇列相反的過程,佇列是先進先出,而棧便是先進後出了,如下圖:  

資料結構---佇列C語言陣列實現

https://blog.csdn.net/morixinguan/article/details/51374296 資料結構---佇列(C語言陣列實現)   佇列是先進先出的過程。簡單地畫一幅畫來描述一下佇列: 一個簡單的、由陣列實現的佇列,可以由以下幾種最基本的操

二叉樹刪除前面節點C語言初始版

#include <stdlib.h> #include <stdio.h> typedef struct node { int key; struct node *left; struct node *right; } Btree; Btr

每日一題C語言基礎篇2

題目描述:使用C語言將一個整型數字轉換成字串並倒序列印,例如:123轉換成字串321,-1234轉換成字串-4321。 程式碼實現: #include <stdio.h> #include

51nod1005大數加法C語言實現大數

大數相加 基本思路是: 1、兩個字串把大數讀進來  然後把每一位字元換成數字存到 x y 數組裡面 2、拿 x  y 陣列從後往前 對應位相加  (注意進位) 相加的結果依次存到 c數組裡 3、然後對c陣列處理 如果最高位小於0  那麼結果肯定是負數  就列印一個負

離散數學真值表c語言程式設計實現

程式碼如下: 廢話不多說: 主要利用二進位制的轉化實現  #include <iostream> #include <math.h> using namespace std; void shuru(char *p,int s); void shu

靜態連結串列插入和刪除操作詳解C語言程式碼實現

本節主要講解靜態連結串列的插入和刪除操作,有關靜態連結串列的詳細講解請閱讀《靜態連結串列及C語言實現》一文。 在講解靜態連結串列的插入和刪除操作之前,我們假設有如下的靜態連結串列: 圖中,array[0] 用作備用連結串列的頭結點,array[1] 用作存放資料的連結串列的頭結點,array[0]