#include <iostream>
#include <vector>
#include <set>
#include <cctype>
#include <algorithm>
#include <valarray>
using namespace std;
/*
数独を総当りで解く関数を2つ作成
1, forを使用したもの
2, 再起を使用したもの
・1~9の数字を使用
・盤面は9*9マス(3*3のブロックが9つ)
・縦 + 横 + ブロック(3*3)において数字が重複しないようにする
・問題が不正な(問題の時点で重複があった)場合問題が不正と出力
・問題に空行が見つかった場合はその行の値を全て無しとみなす
・読み込みが9行未満で終了した場合はそれ以降の行も値を無しとみなす
・解が100個以上見つかった場合は100個目を出力
・解が見つからなかった場合は解無しと出力
問題の受け取りはテキストから一行ずつ
各行につき9文字+改行
値を指定しない場合はドット'.'を指定する
*/
template <int N = 3, class Num = int, Num InvalidValue = -1, Num Empty = 0 >
struct Sudoku {
static const int kBaseSize = N;
typedef Num number_type;
static const number_type kInvalidValue = InvalidValue;
static const number_type kEmpty = Empty;
typedef Sudoku<kBaseSize,number_type,kInvalidValue,kEmpty> this_type;
typedef vector<number_type> SVector;
typedef valarray<number_type> SArray;
typedef vector<SArray> SAVector;
SArray table;
Sudoku() : table(0,N*N*N*N) {}
Sudoku(const this_type& r) : table(r.table) {}
Sudoku(number_type* aProblem) : table(aProblem,N*N*N*N) {}
Sudoku(SVector aProblem) : table(aProblem.data(),N*N*N*N) {}
bool checkPointForRange(int x, int y){
return ! ( x < 0 || N*N <= x || y < 0 || N*N <= y );
}
SAVector relatedCompartmentsOf(int x, int y){
if( !checkPointForRange(x,y) )
return SAVector();
int Y_ = (int)(y/N); // avoid optimization
int X_ = (int)(x/N); // avoid optimization
SAVector coms;
// x axis
coms.emplace_back( table[ gslice(y*N*N + 0, {1, N*N},{N*N,1}) ] );
// y axis
coms.emplace_back( table[ gslice(0 + x, {N*N, 1 },{N*N,1}) ] );
// n*n square
coms.emplace_back( table[ gslice(Y_*N*N*N + X_*N, {N, N },{N*N,1}) ] );
return coms;
}
SVector candidatesOf(int x, int y){
bool has[N*N +1] = {false};
SAVector coms = relatedCompartmentsOf(x,y);
if( coms.empty() ) return SVector();
for_each(coms.begin(),coms.end(), [&has](SArray& a){
for_each(begin(a),end(a), [&has](number_type& a){ has[a] = true; });
});
SVector candidates;
for( int i = 1; i < (N*N+1); i++ )
if( ! has[i] )
candidates.emplace_back(i);
return candidates;
}
private:
bool hasOverlap_(SArray& a){
bool has[N*N +1] = {false};
for(int i = 0; i < N*N; i++ ){
if( a[i] == kEmpty ) continue;
if( has[ a[i] ] ) return true;
has[ a[i] ] = true;
}
return false;
}
public:
bool isOverlapOn( int x, int y ){
SAVector coms = relatedCompartmentsOf(x,y);
return !coms.empty() &&
any_of(coms.begin(),coms.end(),
[&](SArray& a){ return hasOverlap_(a); });
}
bool hasOverlap(){
for( int y = 0, x = 0; y < N*N; x++, y++ ){
if( isOverlapOn((int)(y/N) + (x%N)*N, y) ){
return true;
}
}
return false;
}
bool set( int x, int y, number_type value ){
if( !checkPointForRange(x,y) ||
( ( value < 1 || N*N < value ) && value != kEmpty )
)
return false;
table[y*N*N + x] = value;
return true;
}
number_type get( int x, int y ){
return ( checkPointForRange(x,y) ) ?
table[y*N*N + x]: kInvalidValue;
}
bool isEmpty( int x, int y ){
return get(x,y) == kEmpty;
}
bool setEmpty( int x, int y ){
return set(x,y,kEmpty);
}
static number_type getEmptyValue(){ return kEmpty; }
ostream& show(ostream& os){
string s(N*N+1,0);
for( int i = 0; i < N*N; i++ ){
SArray v = table[ gslice(i*N*N,{1,N*N},{1,1}) ];
v += (number_type)('0');
copy( begin(v), end(v), s.begin() );
replace( begin(s), end(s), '0', ' ' );
os << s << endl;
}
return os;
}
ostream& show(){
return show(cout);
}
};
template <int n = 3>
struct Solver {
typedef Sudoku<n> Su;
typedef typename Su::SVector SVector ;
typedef typename Su::number_type SNumber ;
static const int nn = n*n;
struct Helper {
int x;
int y;
bool succeed;
Su problem;
Su current;
vector<Su> answers;
Helper(Su& probSrc):
x(0), y(0),
succeed(true),
problem(probSrc),
current(problem)
{
if(fixed()) moveNext();
}
bool move(int i, int it){
int cx = x;
int cy = y;
do if( ! problem.checkPointForRange(x+=i,0) ){
if( ! problem.checkPointForRange(0,y+=i) ){
y = cy; x = cx;
return succeed = false;
}
x = it;
} while ( fixed() );
return succeed = true;
}
bool fixed() { return !problem.isEmpty(x,y); }
bool moveNext() { return move(1, 0); }
bool movePrev() { return move(-1,nn-1); }
bool moveFailed() { return !succeed; }
int linearIndex() { return y*nn + x; }
SVector candidate(){ return current.candidatesOf(x,y); }
bool set(SNumber i){ return current.set(x,y,i); }
bool setEmpty() { return current.setEmpty(x,y); }
SNumber get() { return current.get(x,y); }
void pushAnswer() { answers.push_back(current); }
int sizeAnswers() { return answers.size(); }
};
bool readAndSolve(){
vector<int> N(nn*nn,Su::getEmptyValue());
auto N_it = N.begin();
string s;
for( int i = 0; getline(cin,s) && i < n*n; i++ ){
if( s.empty() ){
N_it += nn;
continue;
}
if( s.length() != n*n ){
cout << "error: invalid length of line. len = "
<< s.length() << endl << s << endl;
return false;
}
std::replace(s.begin(),s.end(),'.','0');
if( ! all_of(s.begin(),s.end(),::isdigit) ){
cout << "error: invalid char at line." << s << endl;
return false;
}
N_it = std::transform(s.begin(),s.end(),N_it,
[](char& c){ return (int)(c - '0'); });
}
Su problem(N);
cout << "Problem" << endl;
problem.show();
if( problem.hasOverlap() ){
cout << "Problem has overlap." << endl;
return false;
}
Helper h1(problem);
cout << endl << "<< for loop >>" << endl;
getAnswersByForLoop(h1,100);
showAnswer(h1.answers);
Helper h2(problem);
cout << endl << "<< rec. call >>" << endl;
getAnswersByRecursiveCall(h2,100);
showAnswer(h2.answers);
return true;
}
void showAnswer( vector<Su>& answers ){
if( answers.empty() ){
cout << "No answers were found." << endl;
} else {
cout << answers.size() << " answers were found." << endl;
cout << "The last one is below." << endl;
answers.back().show();
}
}
void getAnswersByForLoop(Helper& h, int limit ){
// max = n^5 * sizeof SNumber
for( SVector cands[nn*nn]; !h.moveFailed(); ){
// forward
{
SVector& cd = cands[h.linearIndex()];
// entered next empty element.
if( cd.empty() )
cd = h.candidate();
// if no candidates, goto backward process.
if( !cd.empty() ){
h.set( cd.back() );
// it could have moved to the next empty element.
if( h.moveNext() ) continue;
// or it is the answer.
h.pushAnswer();
if( h.sizeAnswers() >= limit ){
cout << "Limit exceeds: too many answers. aborted." << endl;
return;
}
// goto backward process.
}
}
// backward
// if prev() is false, then completed. (current is the first element.)
while( h.movePrev() ){
// search candidate.
SVector& cdc = cands[h.linearIndex()];
// current value is the last candidate.
if( cdc.empty() || cdc.front() == h.get() ) {
// there are no answers exist along with this path.
h.setEmpty();
cdc.clear();
} else {
cdc.pop_back();
break;
}
}
}
}
void getAnswersByRecursiveCall(Helper& h, int limit ){
for( auto cd: h.candidate() ){
h.set(cd);
if( h.moveNext() )
getAnswersByRecursiveCall(h,limit);
else {
h.pushAnswer();
if( h.sizeAnswers() >= limit )
cout << "Limit exceeds: too many answers. aborted." << endl;
}
if( h.sizeAnswers() >= limit )
return;
h.setEmpty();
}
h.movePrev();
}
};
int main() {
Solver<3>().readAndSolve();
return 0;
}