蹒跚的第一步
Posted highwaytohell
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了蹒跚的第一步相关的知识,希望对你有一定的参考价值。
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;
测试结果
结果分析
心得体会
#总结下来就是要条理清晰,“要简单不要复杂,要优雅不要丑陋”,这不仅仅是建议,是血泪教训后得的经验。
以上是关于蹒跚的第一步的主要内容,如果未能解决你的问题,请参考以下文章