码迷,mamicode.com
首页 > 其他好文 > 详细

蹒跚的第一步

时间:2019-09-25 00:41:40      阅读:102      评论:0      收藏:0      [点我收藏+]

标签:mamicode   com   文献   遍历   names   取值   text   evel   改进   

GitHub

loading

PSP表格

PSP2.1 Personal Software Process Stages 预估耗时(小时) 实际耗时(小时)
Planning 计划 1 1
Estimate 估计这个任务需要多少时间 26 35
Development 开发 2 2
Analysis 需求分析 (包括学习新技术) 2 2
Design Spec 生成设计文档 1 3
Design Review 设计复审 2 1
Coding Standard 代码规范 (为目前的开发制定合适的规范) 1 1
Design 具体设计 2 1
Coding 具体编码 5 12
Code Review 代码复审 1 1
Test 测试(自我测试,修改代码,提交修改) 2 3
Reporting 报告 2 2
Test Repor 测试报告 2 3
Size Measurement 计算工作量 2 2
Postmortem & Process Improvement Plan 事后总结, 并提出过程改进计划 1 1
合计

起初拿到这个题的时候,我笑不出来,大热天的我手脚冰凉,这一个个字分开来我都认得,组成一个题目我却怎么都看不透—-“命令行传参数”“八宫格”“性能分析”…….
想了一下退学已经来不及了,那只好硬着头皮先做一做。

Sudoku1:完全遍历,暴力解答

就程序而言,我简单理解为三个部分:
文件(input.txt)读入=>处理=>写入文件(output.txt)
查阅了一下文献,写入和写出使用了简单的fostream和instream,这个还是比较好解决的。重头戏是处理,这里我犯了一个很严重的错误,这个错误也花费了我很多很多时间——我使用的最基本的思路。
阶段一:错误的出发点
我最初的思路将整个棋盘的每个子理解为一个结构体node,

struct node{
 int pb[9]={1,2,3,4,5,6,7,8,9};
 int part;
 int num;
};

其中pb数组表示该位置可能的取值,可以直接默认为1-9,(在各阶宫中阶数会限制访问,这样n宫格的每个位置的可能性都是1-n),part用于判断四,六,八,九宫格的各个宫内进行判定,num则用来保存已经确定下的值。这样一来,就可以用最基本的排除法思路来做了。
需要一个 int solo(int *a)函数用于判断数组中是否只存在唯一的一个值,如果是则返回它,否则返回0。

int solo(int *a)
{
 int temp=0,save=0;
 for(int i=0;i<n;i++)if(a[i]!=0)
 {
 temp++;
 save=a[i]; 
 }
if(temp==1)return save; 
 else return 0;
}

需要一个 void kill(int a,int *b)函数用于已知数值缩小同行或者同列其他位置的取值可能性。(将排除掉的值设为0)

void kill(int a,int *b)
{
 for(int i=0;i<n;i++)if(b[i]==a)b[i]=0;}

紧接着就是主要的handle函数,其用途是遍历结构体数组(即所有位置),逐个得到排除后的结果,并且将第一次产生的结果用于第二次遍历,如此循环直到某一次没有发生如何改动,跳出循环。

截至目前,函数已经可以处理三,五阶的宫格,但是再提高阶数就不能完成,即便接下来的部分有使用逐个假设的方法(代码不再列出)。

Sudoku2:递归回溯,清晰优雅

穷则思变,在下一步前查阅了资料,发现这种问题最好是用递归回溯方法,对比之下,顿时感觉到了算法的无穷魅力,于是基本上完全改变了我之前的代码。我两天的思考无疾而终,而这无疾而终的思考又让我产生了新的思考----闭门造车要不得,计划规划要完备。

#include<fstream>
using namespace std;
int Sudoku[9][9];


bool compare(int num,int ch_nowline,int ch_nowcolumn,
    int ch_blockline,int ch_blockcolumn)
{
    for(int i=0;i<=m-1;++i)
    {
        if(Sudoku[ch_nowline][i]==num||Sudoku[i][ch_nowcolumn]==num) 
            return false;
    }
    if(m==9)for(int i=0;i<=2;++i)//宫内检测
    {
        for(int j=0;j<=2;++j)
        {
            if(Sudoku[ch_blockline+i][ch_blockcolumn+j]==num)
                return false;
        }
    }
    if(m==8)for(int i=0;i<=3;++i)
    {
        for(int j=0;j<=1;j++)
        {
            if(Sudoku[ch_blockline+i][ch_blockcolumn+j]==num)
                return false;
        }
    }
    if(m==6)for(int i=0;i<=1;++i)
    {
        for(int j=0;j<=2;j++)
        {
            if(Sudoku[ch_blockline+i][ch_blockcolumn+j])
                return false;
        }
    }
    if(m==4)for(int i=0;i<=1;++i)
    {
        for(int j=0;j<=1;j++)
        {
            if(Sudoku[ch_blockline+i][ch_blockcolumn+j])
                return false;
        }
    }
    return true;
}

bool work(int now_line,int now_column)//主要的处理函数
{
    if(now_line==m)
    {
        return true;//如果将数独解完,返回true 
    }
    else 
    {
        int next_line,next_column,block_line,block_column;
        next_column=now_column+1;
        next_line=(next_column>=m?now_line+1:now_line);
        next_column=(next_column>=m?0:next_column);
        if(Sudoku[now_line][now_column]!=0)//如果当前坐标有数字,则对下一个坐标进行工作 
        {
            if(work(next_line,next_column)) return true;//如果数独最终有解,则不断向前返回true 
        }
        else
        {
            if(m==9)
            {
            block_line=(now_line/3)*3;//计算所在的3*3方格左上角坐标
            block_column=(now_column/3)*3;
            }
            if(m==8)
            {
            block_line=(now_line/4)*4;//计算所在的4*2方格左上角坐标
            block_column=(now_column/2)*2;
            }
            if(m==6)
            {
            block_line=(now_line/2)*2;//计算所在的2*3方格左上角坐标
            block_column=(now_column/3)*3;
            }
            if(m==4)
            {
            block_line=(now_line/2)*2;//计算所在的2*2方格左上角坐标
            block_column=(now_column/2)*2;
            }
            for(int i=1;i<=m;++i)
            {
                if(compare(i,now_line,now_column,block_line,block_column))
                {
                    Sudoku[now_line][now_column]=i;
                    if(work(next_line,next_column)) return true;
                }
            }
            Sudoku[now_line][now_column]=0;//回溯操作 
            return false;
        }
    }
}
void Input(int t,int *save)//将待测数据拷贝进特定数组
{
    for(int i=0;i<=m-1;++i)
    {
        for(int j=0;j<=m-1;++j)
        {
            Sudoku[i][j]=save[t*m*m+i*m+j];
        }
    }
}
void Output(int t,int *save)//将结果拷贝到输出特定数组
{
    for(int i=0;i<=m-1;++i)
    {
        for(int j=0;j<=m-1;++j)
        {
            save[t*m*m+i*m+j]=Sudoku[i][j];
        }
    }
}
int main(int argc,char *argv[])
{
    ifstream infile;
    ofstream outfile;
    m=argv[2][0]-48;
    n=argv[4][0]-48;//获取宫格数和待测棋盘数
    int save[500],cer=0;
    infile.open(argv[6]);
    char ch;
   while(!infile.eof())
    {
       infile.get(ch);
       if('0'<=ch&&ch<='9')save[cer++]=ch-48;
    }
    infile.close();
    for(int t=0;t<n;t++)
    {
        Input(t,save);
        if(work(0,0));
    //  else cout<<"wrong!"<<endl;
        Output(t,save);
    }
    outfile.open(argv[8]);//开始写入 
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<m;j++)
        {
            for(int k=0;k<m;k++)
            {
                outfile<<save[i*m*m+j*m+k]<<"  ";
            }
            outfile<<endl;
        }
        outfile<<endl;
    }
    outfile.close();
    return 0;
 } 

测试结果

技术图片

结果分析

技术图片

心得体会

#总结下来就是要条理清晰,“要简单不要复杂,要优雅不要丑陋”,这不仅仅是建议,是血泪教训后得的经验。

蹒跚的第一步

标签:mamicode   com   文献   遍历   names   取值   text   evel   改进   

原文地址:https://www.cnblogs.com/highwaytohell/p/11542455.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!