Project Euler 96

题目链接如下:https://projecteuler.net/problem=96.

Euler project 96 实际是要求解一个数独的问题。 高中的时候唱唱利用小课的时间做这样的题目,感觉很有意思。不过有一些题目实在太难,可能性太多,最后也不得不放弃。最近在学C++编程,觉得蛮有意思,所以写了一下。

大体思路如下:

1)首先找到一个尚未确定位置,并根据其所在的行,列,和3*3的矩阵的数据来确定其可能的取值;

2)依次验证所选的取值,并更新9*9矩阵,判断下一个位置;

3)重复执行前面两步,直到找不到尚未确定的位置,并返回结果。

这种思路很简单,但有两个易错点:递归的找下一个位置,记得回溯;到达终止条件记得return;


#include "iostream"
#include "fstream"
#include "set"
using namespace::std;
#define N 50
#define NUM 9
int aProblem[N][NUM][NUM];


void fnReadFile()
{
ifstream file;
file.open("p096_sudoku.txt");
char ch;
for(int i=0;i<N;i++)
{
while(1)
{
file.get(ch);
if('0'<=ch&&ch<='9')
{
file.get(ch);
break;
}
}
for(int j=0;j<NUM;j++)
{
file.get(ch);
for(int k=0;k<NUM;k++)
{
file.get(ch);
aProblem[i][j][k]=ch-'0';
}
}
}
file.close();
}


bool find(int arr[][NUM],int& i,int& j)
{
bool flag=0;
for(int ii=0;ii<NUM;ii++)
{
for(int jj=0;jj<NUM;jj++)
{
if(arr[ii][jj]==0)
{
i=ii;
j=jj;
flag=1;
break;
}
}
if(flag==1)
{
break;
}
}
return flag;
}


void fnSudo(int arr[][NUM],int& re)
{
int i;
int j;
if(!find(arr,i,j))
{
re=arr[0][0]*100+arr[0][1]*10+arr[0][2];
return;
}
if(find(arr,i,j))
{
set<int> S;
S.clear();
for(int k=0;k<NUM;k++)
{
if(arr[i][k]>0)
{
S.insert (arr[i][k]);
}
}
for(int k=0;k<NUM;k++)
{
if(arr[k][j]>0)
{
S.insert (arr[k][j]);
}
}
int kk=i/3;
int tt=j/3;
for(int k=kk*3;k<(kk+1)*3;k++)
{
for(int t=tt*3;t<(tt+1)*3;t++)
{
if(arr[k][t]>0)
{
S.insert (arr[k][t]);
}
}
}
for(int k=1;k<NUM+1;k++)
{
int oldsize=S.size ();
S.insert(k);
if(S.size()>oldsize)
{
arr[i][j]=k;
fnSudo(arr,re);
arr[i][j]=0;
}
}
}
}


int main()
{
fnReadFile();
int arr[NUM][NUM];
int sum=0;
int re;
for(int i=0;i<N;i++)
{
for(int j=0;j<NUM;j++)
{
for(int k=0;k<NUM;k++)
{
arr[j][k]=aProblem[i][j][k];
}
}
fnSudo(arr,re);
sum+=re;
}
cout<<"the sum of all problems is:"<<sum<<endl;
ofstream file1;
file1.open("result.txt");
file1<<sum<<endl;
file1.close();
return 1;
}

我还有一种没有实现的想法,用启发式求解。把9*9矩阵作为系统的状态,依次确定每一个状态的后置状态,并跟新OPEN 和 CLOSED 矩阵,直到找到一个所有的数字都不为空状态。

这种想法的难点在于,对结点进行分层,每一层代表该层确定的位置,如第一层是初始矩阵,第2层代表确定的是第1个位置的所有可能的取值后变换的矩阵。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值