编程之美...求解数独

来源:互联网 发布:新站怎么优化排名 编辑:程序博客网 时间:2024/05/06 14:24

  《编程之美》书上并没有这一节,而是我根据“构造数独”一节推广而来的。上一篇我用矩阵的初等变换来构造数独,这一篇我就用DFS(其实我觉得叫递归+回溯更贴切)来求解数独

  具体的步骤我就不啰嗦了,不了解的可以参考任何一本算法书或数据结构的书。递归求解数独并不像网上一些说人的那么慢(一个比较难的数独也是瞬间就解出来了),更不会有栈溢出,处理不当就另当别论。

  这个程序采用文件输入,输入的数据格式为:

004003010
000250000
080000726
020030000
760000805
350867000
905084007
032700900
000905300

其中0表示要填的空。为了操作方便我用一维数组来表示二维数组。

  最后要说明的是,当所有都是要填的空时就相当于构造数独了。当然,这个程序只能构造出一种数独,要使每次构造出不同的数独就需要在算法中加入随机因子了。

CODE

#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include <malloc.h>

void Print(char *grid);
int Next(int index);
char* GetAllowable(int index, int* count);
void Solve(int index);

bool completed = false; //标记是否完成
bool nosolution = false; //标记是否无解
int startIndex = 0;
char solution[81]; //保存数独

int main(int argc, char *argv[])
{
    FILE* file;
    char ch;
    int i = 0;

    //从文件读入
    if((file = fopen("problem.txt","r")) == NULL)
        exit(0);
    while((ch = fgetc(file)) != EOF)
    {
        if(ch != '/n')
        {
            *(solution + i) = ch;
            i++;
        }
    }
    fclose(file);
   
    puts("题目:");
    Print(solution);

    startIndex = Next(-1);
    Solve(startIndex);
   
    if(!nosolution) //有解
    {
        puts("/n解答:");
        Print(solution);
    }
    else
    {
        puts("无解!");
    }
   
    puts("");
    system("pause");
    return 0;
}

//输出数独
void Print(char *grid)
{
    for(int i = 0; i < 81; ++i)
    {
        printf("%2c", grid[i] == '0' ? '_' : grid[i]);
        if(i % 9 == 8) printf("/n");
    }
}

//返回所有在index位置请允许的数字,count为总数
char* GetAllowable(int index, int* count)
{
    int r = index / 9; //行
    int c = index % 9; //列
    bool f[10];

    for(int i = 1; i < 10; ++i) f[i] = true;

    for(int i = 0; i < 9; ++i)
    {
        f[solution[r * 9 + i] - '0'] = false; //行
        f[solution[9 * i + c] - '0'] = false; //列
        f[solution[(r / 3 * 3 + i / 3) * 9 + c / 3 * 3 + i % 3] - '0'] = false; //小九宫格
    }

    int n = 0;
    for(int i = 1; i < 10; ++i)
        if(f[i]) n++;
   
    char* v = NULL;
    if(n > 0)
    {
        v = (char*)malloc(sizeof(char) * n);
        if(v == NULL) exit(0);
        for(int i = 1, j = 0; i < 10; ++i)
            if(f[i]) v[j++] = i + '0';
    }
    *count = n;
    return v;
}

//求解主函数
void Solve(int index)
{
    int n, next;
    char* v = GetAllowable(index, &n);

    if(n == 0) return;
    for(int i = 0; i < n; ++i)
    {
        solution[index] = v[i];
       
        if((next = Next(index)) == 81) //完成
        {
            completed = true;
        }
        else
        {
            Solve(next); //递归
        }

        if(completed == true)
        {
            free(v);
            return;
        }
    }
    free(v);
    solution[index] = '0';

    if(index == startIndex) //无解
    {
        nosolution = true;
    }
}

//找下一个要填的空格
int Next(int index)
{
    while(++index < 81 && solution[index] != '0');
    return index;
}

----------------------------------------------------------