Sudoku sudoku (b) generate final

Hello everyone, today I went on to update the blog.
The main task today is to address the first sub-tasks: to generate final and optimized.
Github complete project Address: https://github.com/surpasss/software-engineering

1. find the final rule

First look at a number of independent legal finality:

1 2 3 4 5 6 7 8 9
7 8 9 1 2 3 4 5 6
4 5 6 7 8 9 1 2 3
9 1 2 3 4 5 6 7 8
6 7 8 9 1 2 3 4 5
3 4 5 6 7 8 9 1 2
8 9 1 2 3 4 5 6 7
5 6 7 8 9 1 2 3 4
2 3 4 5 6 7 8 9 1

  Can be found for this final Sudoku, starting from the second row, each row are the first line of the column to the right 3,6,1,4,7,2,5,8 results. Obviously, for either a full array 1 to 9, can be obtained in this way a final, so you get 9! = 362,880 kinds of finality. But the subject of the request digital upper left corner after school number two is the sum mod 9 + 1, so that only 8! = 40,320 kinds of finality.
  And it can also be found, for any number from 1 to 3 lines a single final, in any order to exchange the three lines, still get a valid final. Similarly, any exchange lines 4-6, lines 7-9 of the sequence may be any exchange of 1 to 3, 4 to 6, 7 to 9 and still meet (but obtained only after an exchange columns may be repeated, because the first line has a non-unique). In addition, the board is divided into lines 1-3, lines 4-6, lines 7-9 that the three, the exchange of any three sequentially obtained which is still valid final column also empathy legitimate. Of course, there are many other laws.
  As a result, the resulting final very much. Since the upper left corner of the figure is fixed, for simplicity, the order may be arbitrarily switched lines 4-6, lines 7-9 of the sequence, there is obtained the number of final 40320 × 3! × 3! = 1,451,520 kinds, has more than 1e6. And generates the final and do not repeat, because the first 8! The first row is not repeated, but every other row is determined only by the first row.

2. Design and Implementation

  Through the analysis, the idea is to generate a final permutation to obtain a full 1 to 9, as line 1; line 2 and the third row of each column to the right, respectively, the first line obtained by three and six. Line 4 through line 6 to the first row of each column to the right full array {1,4,7} to obtain the composition. Similarly, line 7 to line 9 of a first row of each column to the right by {2, full array consisting of 5,8} obtained. Until the final number is generated to meet the requirements to exit the loop. So far the functionality is implemented given call graph, as shown below:
  
  wherein CreateSudoku this function is performed to generate final feature according to the command input line is determined, and then the cycle call TranslateRow function generates a temporary and final storage. First look at how to generate a full array 1 to 9 as the first row in the CreateSudoku function, which may be achieved by next_permutation STL library function calls, function next_permutation current dictionary in accordance with the array are arranged to produce a full sequence, thus ensuring after each call an array of unique details, please see this link next_permutation usage . So for an array after each call next_permutation cycle 6 × 6 generates a function call to TranslateRow final.

3. Optimize Performance

  Encoded initial stage, we will certainly consider each stored final generated by a 9 × 9 integer array, and then write the file immediately. I started the same way, coding is complete, so that it generates 1000 final, VS comes with performance analysis tools get this running time of 2.206 seconds, the number of questions asked within 60 seconds, just started feeling okay. Generate 1e6 but not over the final time-consuming, run shot as follows:
  
  It can be seen running time of 1 minute 44 seconds, to observe time-consuming function table below can be seen the function printf accounted for 97.32% of the running time call graph of the function is as follows:
  
  printf function is to generate the final written document, read several other sister school seniors to write online blog that frequently write to the file will spend a lot of time, so consider using a sufficient large character buffer array to hold each of the final zero, the final write-once. After simple to modify the code, performance analysis again, screenshot:
  
  you can see the run time of 13.413 seconds, significantly reduced compared to before, I have a little surprise wonder at the same time. Because printf function still accounted for 86.97 percent uptime, how files are write-once accounted for such a large proportion of the string it will not be too long, but some seniors running time is the single digits it, or explain the problem in on printf. Had an idea, I put the printf function into the output stream cout C ++ in the only change this place, and performance analysis again, actually had a surprising result, as shown below:
  
  you can see the running time of only 4.301 seconds , write to file accounting for 58.73 percent of the running time, this should not have to change it. With reduced when writing files accounted for, TranslateRow function accounted for 36.35% of the time, to see each line of code accounts for the ratio, as shown:
  
  
  you can see most of the running time is spent filling map and finally map the integer array array the value stored in the buffer string. This is actually taking a detour to be rounding map array, directly to the numeric character string stored in the buffer, perhaps time will be shorter. After simple to modify the code, performance analysis again, screenshot:
  
  Sure enough, this time is reduced again, reaching 3.857 seconds, cout output stream accounted for 68.00 percent uptime, TranslateRow function accounted for 26.14 percent uptime. Performance is improved compared to the previous Again, since the further low profile of the machine, on the machine performance will be less operating time, a program should achieve a good performance.
  In summary, for the generation of final, I did a three optimization, the optimization is to save all of the first final with a long string, and then write the file disposable; second optimization is to replace the printf function with the COUT output stream (described : I open the file with freopen function, so you can manipulate files directly printf function console, the details link to see this difference of freopen and fopen ); third place optimization is credited directly to the final string buffer, minus out of the middle of the cycle.

4. Final Code

#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <iostream>
using namespace std;

int init[9] = { 3, 1, 2, 4, 5, 6, 7, 8, 9 };//第1行。第1个数字固定,第2-9个数字从小到大布置

//均通过第1行的各列右移,4-6行、7-9行各6次变换
int row_trans_0[3] = { 0, 3, 6 };//生成1-3行的右移列数
int row_trans_1[6][3] = { {1, 4, 7}, {1, 7, 4}, {4, 1, 7}, {4, 7, 1}, {7, 1, 4}, {7, 4, 1} };//生成4-6行的右移列数
int row_trans_2[6][3] = { {2, 5, 8}, {2, 8, 5}, {5, 2, 8}, {5, 8, 2}, {8, 2, 5}, {8, 5, 2} };//生成7-9行的右移列数

char buffer[165000000];//缓冲字符串
int pos = 0;//缓冲字符串的当前写入位置

void TranslateRow(int trans_1, int trans_2)//trans_1为row_trans_1的第一维位置,trans_2为row_trans_2的第一维位置
{
    for (int i = 0; i < 3; i++)//写入1-3行至buffer中
    {
        int trans = 9 - row_trans_0[i];
        for (int j = 0; j < 8; j++)
        {
            buffer[pos++] = init[(j + trans) % 9] + '0';
            buffer[pos++] = ' ';
        }
        buffer[pos++] = init[(9 + trans) % 9] + '0';
        buffer[pos++] = '\n';
    }
    for (int i = 3; i < 6; i++)//写入4-6行至buffer中
    {
        int trans = 9 - row_trans_1[trans_1][i - 3];
        for (int j = 0; j < 8; j++)
        {
            buffer[pos++] = init[(j + trans) % 9] + '0';
            buffer[pos++] = ' ';
        }
        buffer[pos++] = init[(9 + trans) % 9] + '0';
        buffer[pos++] = '\n';
    }
    for (int i = 6; i < 9; i++)//写入7-9行至buffer中
    {
        int trans = 9 - row_trans_2[trans_2][i - 6];
        for (int j = 0; j < 8; j++)
        {
            buffer[pos++] = init[(j + trans) % 9] + '0';
            buffer[pos++] = ' ';
        }
        buffer[pos++] = init[(9 + trans) % 9] + '0';
        buffer[pos++] = '\n';
    }
}

void CreateSudoku(int n)//需生成的终局个数
{
    freopen("sudoku.txt", "w", stdout);
    int num = 0;//已生成的终局个数
    do
    {
        for (int i = 0; i < 6; i++)
        {
            for (int j = 0; j < 6; j++)
            {
                num += 1;
                TranslateRow(i, j);
                if (num < n)//已生成终局个数未达标,终局之间换行
                {
                    buffer[pos++] = '\n';
                }
                else//生成终局个数已达标,写入文件并退出
                {
                    cout << buffer;
                    fclose(stdout);
                    return;
                }
            }
        }
    } while (next_permutation(init + 1, init + 9));//从init第二个数字开始全排列
}

Guess you like

Origin www.cnblogs.com/zyj-surpass/p/12104248.html