利用程序随机构造N个已解答的数独棋盘

一、作业要求

1、利用程序随机构造N个已知的数独棋盘

2、键盘输入数独棋盘的个数N(0<n<1000000)

3、输出到susotiku.txt文件中,每个数独棋盘隔一#include <stdio.h>

实现代码:


#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <iostream>

using namespace std;

#define SIZE 9

int get_sudoku(int temp[SIZE][SIZE]);
void cleanup(int temp[SIZE][SIZE]);
void output_sudoku(int temp[SIZE][SIZE]);
int check_sudoku(int temp[SIZE][SIZE], int i, int j, int k);


int sudo[SIZE][SIZE] = { 0 };

int main(int argc, char *argv[]) {
    int i, n;
    cout << "请输入数独个数:";
    cin >> n;
    srand(time(NULL));
    for (i = 0; i < n; i++) {
        do {
            cleanup(sudo);
        } while (get_sudoku(sudo) == 0);  //如果数独生成失败,返回结果为0,则清空sudo数组,继续再试直到成功
        output_sudoku(sudo);
    }
    return 0;
}

//使数独全部清零
void cleanup(int temp[SIZE][SIZE]) {
    int i, j;
    for (i = 0; i < SIZE; i++) {
        for (j = 0; j < SIZE; j++) {
            temp[i][j] = 0;
        }
    }
}

int get_sudoku(int temp[SIZE][SIZE]) {
    int i, j, m, random;
    random = rand() % SIZE + 1;//随机生成数独第一行第一列的数
                               //循环每一行
    for (i = 0; i < SIZE; i++) {
        //循环每一列
        for (j = 0; j < SIZE; j++) {
            m = 0;
            //判断此随机数是否能够使用,如果能使用跳出循环,否则继续循环
            while (check_sudoku(temp, i, j, random) == 0) {
                random = rand() % SIZE + 1;  //生成一个0-SIZE的随机数
                m++;
                //如果同一个位置失败一百次,则重新开始
                if (m > 80) return 0;
            }
            temp[i][j] = random;//此数已经通过检查,放入数独
        }
    }
    return 1;
}

void output_sudoku(int temp[SIZE][SIZE]) {
    int i, j;
    FILE *fp;
    //数独输出到屏幕
    for (i = 0; i < SIZE; i++) {
        for (j = 0; j < SIZE; j++) {
            cout << temp[i][j];
            cout << " ";
        }
        cout << "\n";
    }
    cout << "\n";
    //数独输出到文档
    if ((fp = fopen("sudotiku.txt", "a+")) == NULL) {
        cout << "Can't opent file!";
        exit(1);
    }
    for (i = 0; i < SIZE; i++) {
        for (j = 0; j < SIZE; j++) {
            fprintf(fp, "%d ", temp[i][j]);
        }
        fprintf(fp, "\n");
    }
    fprintf(fp, "\n");
    fclose(fp);
}

//判断是否可以将第i行、第j列的数设为k
int check_sudoku(int temp[SIZE][SIZE], int i, int j, int k) {
    int m, n;
    //判断行
    for (n = 0; n < SIZE; n++) {
        if (temp[i][n] == k)
            return 0;
    }
    //判断列
    for (m = 0; m < SIZE; m++) {
        if (temp[m][j] == k)
            return 0;
    }
    //判断所在九宫格
    int t1 = (i / 3) * 3, t2 = (j / 3) * 3;
    for (m = t1; m < t1 + 3; m++) {
        for (n = t2; n < t2 + 3; n++) {
            if (temp[m][n] == k)
                return 0;
        }
    }
    return 1;
}

运行结果:

 

二、程序分析:

分析:九宫格数独棋盘要求每行数字唯一,每列数字唯一,并且每个九宫格数字唯一,代码首先用一个rand函数%9即生成一个1到9的数字,通过构造check_sudoku(temp[][],i,j)函数确定随机生成的数符合数独规则则放入到数独数组中,否则继续生成并判断,如果同一位置失败超过100次则清空数独数组并重新构造;功能:经测试程序能够实现输出n个数独棋盘的目的;缺陷:穷举法程序执行效率低下,例如当一个位置无解,那么能否通过回溯法改变该位置的上一个元素的值而不是清空该数组来实现搜索呢?

三、心得:

1、希望通过后续的算法学习进一步改进自己的代码,提高程序运行效率;

2、由于本人C++不是太熟练,不懂如何输出结果并生成.txt文件,百度了下,知道程序的开头要引用fstream头文件,然后用ofstream来输出;

3、此次练习让我了解到学习算法的重要性,之前一直认为算法部分较难,有畏难心理,通过本次练习让我进一步体会了程序=数据结构+算法这句话,也让我知道算法这门课一定要学好并多实践;

四、重要技能:

五、代码已提交到coding.net,可以下载。

https://coding.net/u/dhlg_201810812007/p/sugarfei_123/git/blob/master/jiugongge

 

posted on 2018-10-07 14:43  小雪zzz  阅读(364)  评论(1编辑  收藏  举报