数独求解(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()


  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值