#include <iostream>
#include <vector>
#include <cstdint>
#include <algorithm>
#include <random>
#include <iterator>
typedef std::vector<std::uint32_t> DType;
typedef std::vector<DType> Grid;
typedef std::vector<Grid> RType;
typedef std::vector < std::vector<DType>> Cube;
#ifdef _WIN32
#include <Windows.h>//ms windows os only.
void gotoxy(int X, int Y) {//カーソルを移動させる関数です。環境によってはエスケープシーケンスが使えるのでそれに置き換えることもできます。
COORD Pos = { static_cast<SHORT>(X),static_cast<SHORT>(Y) };//WINDOWS定義の構造体です。
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), Pos);//windows定義の関数です。カーソルを移動します。
return;
}
#else
void gotoxy(int X, int Y) {
return;
}
#endif
Grid MakeProblem() {
Grid R{
{ 1,5,0,0,8,6,0,7,0, },
{ 7,0,8,9,0,0,0,0,0, },
{ 0,9,0,5,0,0,0,8,1, },
{ 9,0,0,0,0,8,1,0,6, },
{ 0,0,1,0,2,0,0,9,0, },
{ 0,7,5,6,0,0,2,0,0, },
{ 5,0,6,0,4,0,0,2,0, },
{ 3,0,0,1,0,2,5,0,0, },
{ 0,4,0,8,0,0,0,0,9, },
};
return R;
}
Grid MakeGrid() {
Grid G(9);
for (auto& o : G) {
o.assign(9, 0);
}
return G;
}
Cube MakeCube() {
DType D{ 1,2,3,4,5,6,7,8,9 };
Cube C(9);
for (auto& oo : C) {
oo.resize(9);
for (auto& o : oo) {
o = D;
}
}
return C;
}
Cube ReduceCube(const Cube& Cu, const Grid& P) {
Cube C = Cu;
for (std::size_t i = 0; i < P.size(); i++) {
for (std::size_t j = 0; j < P[i].size(); j++) {
if (P[i][j] != 0) {
C[i][j].clear();
C[i][j].push_back(P[i][j]);
}
}
}
for (std::size_t i = 0; i < C.size(); i++) {
for (std::size_t j = 0; j < C[i].size(); j++) {
if (C[i][j].size() != 1)continue;
for (std::size_t k = 0; k < P.size(); k++) {
if (C[i][k].size() == 1) continue;
auto it = std::find(C[i][k].begin(), C[i][k].end(), C[i][j][0]);
if (it != C[i][k].end()) {
C[i][k].erase(it);
}
}
for (std::size_t k = 0; k < P.size(); k++) {
if (C[k][j].size() == 1) continue;
auto it = std::find(C[k][j].begin(), C[k][j].end(), C[i][j][0]);
if (it != C[k][j].end()) {
C[k][j].erase(it);
}
}
}
}
std::size_t X = 0;
std::size_t Y = 0;
for (std::size_t Y = 0; Y < 3; Y++) {
for (std::size_t X = 0; X < 3; X++) {
for (std::size_t i = 0; i < 3; i++) {
for (std::size_t j = 0; j < 3; j++) {
if (C[Y * 3 + i][X * 3 + j].size() != 1)continue;
for (std::size_t k = 0; k < 3; k++) {
for (std::size_t l = 0; l < 3; l++) {
if (C[Y * 3 + k][X * 3 + l].size() == 1)continue;
auto it = std::find(C[Y * 3 + k][X * 3 + l].begin(), C[Y * 3 + k][X * 3 + l].end(), C[Y * 3 + i][X * 3 + j][0]);
if (it != C[Y * 3 + k][X * 3 + l].end()) {
C[Y * 3 + k][X * 3 + l].erase(it);
}
}
}
}
}
}
}
return C;
}
bool IsAnswer(Grid P) {
DType D;
for (std::size_t Y = 0; Y < 3; Y++) {
for (std::size_t X = 0; X < 3; X++) {
for (std::size_t i = 0; i < 3; i++) {
for (std::size_t j = 0; j < 3; j++) {
D.push_back(P[Y * 3 + i][X * 3 + j]);
}
}
std::sort(D.begin(), D.end());
D.erase(std::unique(D.begin(), D.end()), D.end());
if (D.size() != 9)return false;
}
}
for (std::size_t i = 0; i < P.size(); i++) {
D.clear();
for (std::size_t j = 0; j < P[i].size(); j++) {
D.push_back(P[i][j]);
}
std::sort(D.begin(), D.end());
D.erase(std::unique(D.begin(), D.end()), D.end());
if (D.size() != 9)return false;
}
for (std::size_t i = 0; i < P.size(); i++) {
D.clear();
for (std::size_t j = 0; j < P[i].size(); j++) {
D.push_back(P[j][i]);
}
std::sort(D.begin(), D.end());
D.erase(std::unique(D.begin(), D.end()), D.end());
if (D.size() != 9)return false;
}
return true;
}
Grid CubeToGrid(const Cube& C, const Grid G) {
Grid R = MakeGrid();
for (std::size_t i = 0; i < G.size(); i++) {
for (std::size_t j = 0; j < G[i].size(); j++) {
R[i][j] = C[i][j][G[i][j]];
}
}
return R;
}
Grid CubeToProblem(const Cube& C) {
Grid G = MakeGrid();
for (std::size_t i = 0; i < G.size(); i++) {
for (std::size_t j = 0; j < G[i].size(); j++) {
if (C[i][j].size() == 1) {
G[i][j] = C[i][j][0];
}
else {
G[i][j] = 0;
}
}
}
return G;
}
bool ShowList(Cube& C) {
std::size_t i = 1;
double D = 0;
for (auto& ooo : C) {
for (auto& oo : ooo) {
std::cout << '[' << i << ':';
i++;
D += oo.size();
for (auto& o : oo) {
std::cout << o << ',';
}
std::cout << ']';
}
std::cout << std::endl;
}
std::cout << D / 81.0 << std::endl;
return true;
}
bool Show(const Grid& G) {
for (auto& oo : G) {
for (auto& o : oo) {
std::cout << o;
}
std::cout << std::endl;
}
std::cout << std::endl;
std::cout << std::endl;
return true;
}
DType GetAntiIntersection(DType A ,const DType& B){//積集合を取り除く??
for (auto& o : B) {
auto it = std::find(A.begin(), A.end(), o);
if(it != A.end())A.erase(it);
}
return A;
}
bool IsHorizonValid(const Grid& G,std::size_t V) {//横方向検査
DType D;
for (std::size_t i = 0; i < G[V].size(); i++) {
if(G[V][i]!=0)D.push_back(G[V][i]);
}
std::sort(D.begin(), D.end());
D.erase(std::unique(D.begin(), D.end()), D.end());
return D.size() == 9 ? true : false;
}
DType GetHorizonUsing(const Grid& G,std::size_t V) {//横方向検査
DType D;
for (std::size_t i = 0; i < G[V].size(); i++) {
if(G[V][i]!=0) D.push_back(G[V][i]);
}
return D;
}
bool HaveHorizonZero(const Grid& G,std::size_t V) {//横方向検査
DType D;
for (std::size_t i = 0; i < G[V].size(); i++) {
if (G[V][i] == 0)return true;
}
return false;
}
bool IsVerticalValid(const Grid& G,std::size_t H) {//縦方向検査
DType D;
for (std::size_t i = 0; i < G.size(); i++) {
if(G[i][H]!= 0)D.push_back(G[i][H]);
}
std::sort(D.begin(), D.end());
D.erase(std::unique(D.begin(), D.end()), D.end());
return D.size() == 9 ? true : false;
}DType GetVerticalUsing(const Grid& G,std::size_t H) {//横方向検査
DType D;
DType T{ 0,1,2,3,4,5,6,7,8 };
for (std::size_t i = 0; i < G.size(); i++) {
if(G[i][H]!= 0)D.push_back(G[i][H]);
}
return D;
}
bool HaveVerticalZero(const Grid& G,std::size_t H) {//縦方向検査
DType D;
for (std::size_t i = 0; i < G.size(); i++) {
if (G[i][H] == 0)return true;
}
return false;
}
bool IsBlockValid(const Grid& G, std::size_t X, std::size_t Y) {//3x3検査
DType D;
for (std::size_t i = 0; i < 3; i++) {
for (std::size_t j = 0; j < 3; j++) {
if(G[Y*3+i][X*3+j] !=0)D.push_back(G[Y*3+i][X*3+j]);
}
}
std::sort(D.begin(), D.end());
D.erase(std::unique(D.begin(), D.end()), D.end());
return D.size() == 9 ? true : false;
}
DType GetBlockUsing(const Grid& G,std::size_t X,std::size_t Y) {//横方向検査
DType D;
for (std::size_t i = 0; i < 3; i++) {
for (std::size_t j = 0; j < 3; j++) {
if(G[Y*3+i][X*3+j] !=0) D.push_back(G[Y*3+i][X*3+j]);
}
}
return D;
}
bool HaveBlockNumber(const Grid& G, std::size_t X, std::size_t Y, std::size_t N) {//横方向検査
DType D;
for (std::size_t i = 0; i < 3; i++) {
for (std::size_t j = 0; j < 3; j++) {
if (G[Y * 3 + i][X * 3 + j] == N)return true;
}
}
return false;
}
bool HaveBlockZero(const Grid& G, std::size_t X, std::size_t Y) {//3x3検査
DType D;
for (std::size_t i = 0; i < 3; i++) {
for (std::size_t j = 0; j < 3; j++) {
if (G[Y * 3 + i][X * 3 + j] == 0)return true;
}
}
return false;
}
bool Search_r(Grid& G, int Deep, RType& R, std::size_t& C) {
C++;
gotoxy(11, 0);
// std::cout << C << std::endl;
if (Deep >= 81) {
gotoxy(0, 0);
//Show(G);
if (IsAnswer(G)) {
R.push_back(G);
std::cout << "find!!" << std::endl;
return true;
}
return false;
}
static const DType T{ 1,2,3,4,5,6,7,8,9 };
std::size_t MX = (Deep % 9) % 3;
std::size_t MY = (Deep % 9) / 3;
std::size_t BX = (Deep / 9) % 3;
std::size_t BY = (Deep / 9) / 3;
auto BU = GetBlockUsing(G, BX, BY);
auto HU = GetHorizonUsing(G, BY*3+MY);
auto VU = GetVerticalUsing(G, BX*3 + MX);
DType AI;
if (G[BY*3 + MY][BX*3 + MX] != 0) {
return Search_r(G, Deep + 1, R,C);
}
std::copy(BU.begin(), BU.end(), std::back_inserter(AI));
std::copy(HU.begin(), HU.end(), std::back_inserter(AI));
std::copy(VU.begin(), VU.end(), std::back_inserter(AI));
std::sort(AI.begin(), AI.end());
AI.erase(std::unique(AI.begin(), AI.end()), AI.end());
DType D = GetAntiIntersection(T, AI);
auto WG = G;
if (D.size() == 0) return false;
for (std::size_t i = 0; i < D.size(); i++) {
WG[BY*3 + MY][BX*3 + MX] = D[i];
gotoxy(0, 0);
// Show(WG);
Search_r(WG, Deep + 1, R,C);
}
return false;
}
bool Search(Grid& G, RType& R) {
int Deep = 0;
std::size_t C=0;
return Search_r(G, Deep, R, C);
}
RType MakeHoge(Grid G) {
Cube Cu = MakeCube();
Cube C = ReduceCube(Cu, G);
Grid V = MakeGrid();
RType R;
Grid B = G;
Grid D;
std::uint64_t Co = 0;
std::uint64_t Find = 1;
do {
D = B;
B = CubeToProblem(C);
C = ReduceCube(C, B);
} while (D != B);
gotoxy(0, 11);
// Show(B);
// ShowList(C);
auto A = CubeToProblem(C);
gotoxy(0, 11);
// Show(A);
Search(A, R);
return R;
}
int main() {
Grid G = MakeProblem();
RType R;
Show(G);
R = MakeHoge(G);
for (auto& o : R) {
gotoxy(0, 0);
Show(o);
}
return 0;
}
I2luY2x1ZGUgPGlvc3RyZWFtPgojaW5jbHVkZSA8dmVjdG9yPgojaW5jbHVkZSA8Y3N0ZGludD4KI2luY2x1ZGUgPGFsZ29yaXRobT4KI2luY2x1ZGUgPHJhbmRvbT4KI2luY2x1ZGUgPGl0ZXJhdG9yPgoKdHlwZWRlZiBzdGQ6OnZlY3RvcjxzdGQ6OnVpbnQzMl90PiBEVHlwZTsKdHlwZWRlZiBzdGQ6OnZlY3RvcjxEVHlwZT4gR3JpZDsKdHlwZWRlZiBzdGQ6OnZlY3RvcjxHcmlkPiBSVHlwZTsKdHlwZWRlZiBzdGQ6OnZlY3RvciA8IHN0ZDo6dmVjdG9yPERUeXBlPj4gQ3ViZTsKI2lmZGVmIF9XSU4zMgojaW5jbHVkZSA8V2luZG93cy5oPi8vbXMgd2luZG93cyBvcyBvbmx5Lgp2b2lkIGdvdG94eShpbnQgWCwgaW50IFkpIHsvL+OCq+ODvOOCveODq+OCkuenu+WLleOBleOBm+OCi+mWouaVsOOBp+OBmeOAgueSsOWig+OBq+OCiOOBo+OBpuOBr+OCqOOCueOCseODvOODl+OCt+ODvOOCseODs+OCueOBjOS9v+OBiOOCi+OBruOBp+OBneOCjOOBq+e9ruOBjeaPm+OBiOOCi+OBk+OBqOOCguOBp+OBjeOBvuOBmeOAggoJQ09PUkQgUG9zID0geyBzdGF0aWNfY2FzdDxTSE9SVD4oWCksc3RhdGljX2Nhc3Q8U0hPUlQ+KFkpIH07Ly9XSU5ET1dT5a6a576p44Gu5qeL6YCg5L2T44Gn44GZ44CCCglTZXRDb25zb2xlQ3Vyc29yUG9zaXRpb24oR2V0U3RkSGFuZGxlKFNURF9PVVRQVVRfSEFORExFKSwgUG9zKTsvL3dpbmRvd3Plrprnvqnjga7plqLmlbDjgafjgZnjgILjgqvjg7zjgr3jg6vjgpLnp7vli5XjgZfjgb7jgZnjgIIKCXJldHVybjsKfQojZWxzZQp2b2lkIGdvdG94eShpbnQgWCwgaW50IFkpIHsKCXJldHVybjsKfQojZW5kaWYKCgpHcmlkIE1ha2VQcm9ibGVtKCkgewoJR3JpZCBSewoJCXsgMSw1LDAsMCw4LDYsMCw3LDAsIH0sCgkJeyA3LDAsOCw5LDAsMCwwLDAsMCwgfSwKCQl7IDAsOSwwLDUsMCwwLDAsOCwxLCB9LAoJCXsgOSwwLDAsMCwwLDgsMSwwLDYsIH0sCgkJeyAwLDAsMSwwLDIsMCwwLDksMCwgfSwKCQl7IDAsNyw1LDYsMCwwLDIsMCwwLCB9LAoJCXsgNSwwLDYsMCw0LDAsMCwyLDAsIH0sCgkJeyAzLDAsMCwxLDAsMiw1LDAsMCwgfSwKCQl7IDAsNCwwLDgsMCwwLDAsMCw5LCB9LAoJfTsKCglyZXR1cm4gUjsKCn0KCkdyaWQgTWFrZUdyaWQoKSB7CglHcmlkIEcoOSk7Cglmb3IgKGF1dG8mIG8gOiBHKSB7CgkJby5hc3NpZ24oOSwgMCk7Cgl9CglyZXR1cm4gRzsKfQpDdWJlIE1ha2VDdWJlKCkgewoJRFR5cGUgRHsgMSwyLDMsNCw1LDYsNyw4LDkgfTsKCUN1YmUgQyg5KTsKCWZvciAoYXV0byYgb28gOiBDKSB7CgkJb28ucmVzaXplKDkpOwoJCWZvciAoYXV0byYgbyA6IG9vKSB7CgkJCW8gPSBEOwoJCX0KCX0KCglyZXR1cm4gQzsKfQoKQ3ViZSBSZWR1Y2VDdWJlKGNvbnN0IEN1YmUmIEN1LCBjb25zdCBHcmlkJiBQKSB7CglDdWJlIEMgPSBDdTsKCWZvciAoc3RkOjpzaXplX3QgaSA9IDA7IGkgPCBQLnNpemUoKTsgaSsrKSB7CgkJZm9yIChzdGQ6OnNpemVfdCBqID0gMDsgaiA8IFBbaV0uc2l6ZSgpOyBqKyspIHsKCQkJaWYgKFBbaV1bal0gIT0gMCkgewoJCQkJQ1tpXVtqXS5jbGVhcigpOwoJCQkJQ1tpXVtqXS5wdXNoX2JhY2soUFtpXVtqXSk7CgkJCX0KCgkJfQoJfQoJZm9yIChzdGQ6OnNpemVfdCBpID0gMDsgaSA8IEMuc2l6ZSgpOyBpKyspIHsKCQlmb3IgKHN0ZDo6c2l6ZV90IGogPSAwOyBqIDwgQ1tpXS5zaXplKCk7IGorKykgewoJCQlpZiAoQ1tpXVtqXS5zaXplKCkgIT0gMSljb250aW51ZTsKCgoJCQlmb3IgKHN0ZDo6c2l6ZV90IGsgPSAwOyBrIDwgUC5zaXplKCk7IGsrKykgewoJCQkJaWYgKENbaV1ba10uc2l6ZSgpID09IDEpIGNvbnRpbnVlOwoJCQkJYXV0byBpdCA9IHN0ZDo6ZmluZChDW2ldW2tdLmJlZ2luKCksIENbaV1ba10uZW5kKCksIENbaV1bal1bMF0pOwoJCQkJaWYgKGl0ICE9IENbaV1ba10uZW5kKCkpIHsKCQkJCQlDW2ldW2tdLmVyYXNlKGl0KTsKCQkJCX0KCQkJfQoJCQlmb3IgKHN0ZDo6c2l6ZV90IGsgPSAwOyBrIDwgUC5zaXplKCk7IGsrKykgewoJCQkJaWYgKENba11bal0uc2l6ZSgpID09IDEpIGNvbnRpbnVlOwoJCQkJYXV0byBpdCA9IHN0ZDo6ZmluZChDW2tdW2pdLmJlZ2luKCksIENba11bal0uZW5kKCksIENbaV1bal1bMF0pOwoJCQkJaWYgKGl0ICE9IENba11bal0uZW5kKCkpIHsKCQkJCQlDW2tdW2pdLmVyYXNlKGl0KTsKCQkJCX0KCQkJfQoJCX0KCX0KCXN0ZDo6c2l6ZV90IFggPSAwOwoJc3RkOjpzaXplX3QgWSA9IDA7Cglmb3IgKHN0ZDo6c2l6ZV90IFkgPSAwOyBZIDwgMzsgWSsrKSB7CgkJZm9yIChzdGQ6OnNpemVfdCBYID0gMDsgWCA8IDM7IFgrKykgewoKCQkJZm9yIChzdGQ6OnNpemVfdCBpID0gMDsgaSA8IDM7IGkrKykgewoJCQkJZm9yIChzdGQ6OnNpemVfdCBqID0gMDsgaiA8IDM7IGorKykgewoKCQkJCQlpZiAoQ1tZICogMyArIGldW1ggKiAzICsgal0uc2l6ZSgpICE9IDEpY29udGludWU7CgoJCQkJCWZvciAoc3RkOjpzaXplX3QgayA9IDA7IGsgPCAzOyBrKyspIHsKCQkJCQkJZm9yIChzdGQ6OnNpemVfdCBsID0gMDsgbCA8IDM7IGwrKykgewoJCQkJCQkJaWYgKENbWSAqIDMgKyBrXVtYICogMyArIGxdLnNpemUoKSA9PSAxKWNvbnRpbnVlOwoJCQkJCQkJYXV0byBpdCA9IHN0ZDo6ZmluZChDW1kgKiAzICsga11bWCAqIDMgKyBsXS5iZWdpbigpLCBDW1kgKiAzICsga11bWCAqIDMgKyBsXS5lbmQoKSwgQ1tZICogMyArIGldW1ggKiAzICsgal1bMF0pOwoJCQkJCQkJaWYgKGl0ICE9IENbWSAqIDMgKyBrXVtYICogMyArIGxdLmVuZCgpKSB7CgkJCQkJCQkJQ1tZICogMyArIGtdW1ggKiAzICsgbF0uZXJhc2UoaXQpOwoKCQkJCQkJCX0KCQkJCQkJfQoJCQkJCX0KCQkJCX0KCQkJfQoJCX0KCX0KCXJldHVybiBDOwp9CgoKYm9vbCBJc0Fuc3dlcihHcmlkIFApIHsKCURUeXBlIEQ7Cglmb3IgKHN0ZDo6c2l6ZV90IFkgPSAwOyBZIDwgMzsgWSsrKSB7CgkJZm9yIChzdGQ6OnNpemVfdCBYID0gMDsgWCA8IDM7IFgrKykgewoJCQlmb3IgKHN0ZDo6c2l6ZV90IGkgPSAwOyBpIDwgMzsgaSsrKSB7CgkJCQlmb3IgKHN0ZDo6c2l6ZV90IGogPSAwOyBqIDwgMzsgaisrKSB7CgkJCQkJRC5wdXNoX2JhY2soUFtZICogMyArIGldW1ggKiAzICsgal0pOwoJCQkJfQoJCQl9CgkJCXN0ZDo6c29ydChELmJlZ2luKCksIEQuZW5kKCkpOwoJCQlELmVyYXNlKHN0ZDo6dW5pcXVlKEQuYmVnaW4oKSwgRC5lbmQoKSksIEQuZW5kKCkpOwoJCQlpZiAoRC5zaXplKCkgIT0gOSlyZXR1cm4gZmFsc2U7CgkJfQoJfQoKCWZvciAoc3RkOjpzaXplX3QgaSA9IDA7IGkgPCBQLnNpemUoKTsgaSsrKSB7CgkJRC5jbGVhcigpOwoJCWZvciAoc3RkOjpzaXplX3QgaiA9IDA7IGogPCBQW2ldLnNpemUoKTsgaisrKSB7CgkJCUQucHVzaF9iYWNrKFBbaV1bal0pOwoJCX0KCQlzdGQ6OnNvcnQoRC5iZWdpbigpLCBELmVuZCgpKTsKCQlELmVyYXNlKHN0ZDo6dW5pcXVlKEQuYmVnaW4oKSwgRC5lbmQoKSksIEQuZW5kKCkpOwoJCWlmIChELnNpemUoKSAhPSA5KXJldHVybiBmYWxzZTsKCX0KCWZvciAoc3RkOjpzaXplX3QgaSA9IDA7IGkgPCBQLnNpemUoKTsgaSsrKSB7CgkJRC5jbGVhcigpOwoJCWZvciAoc3RkOjpzaXplX3QgaiA9IDA7IGogPCBQW2ldLnNpemUoKTsgaisrKSB7CgkJCUQucHVzaF9iYWNrKFBbal1baV0pOwoJCX0KCQlzdGQ6OnNvcnQoRC5iZWdpbigpLCBELmVuZCgpKTsKCQlELmVyYXNlKHN0ZDo6dW5pcXVlKEQuYmVnaW4oKSwgRC5lbmQoKSksIEQuZW5kKCkpOwoJCWlmIChELnNpemUoKSAhPSA5KXJldHVybiBmYWxzZTsKCX0KCglyZXR1cm4gdHJ1ZTsKfQpHcmlkIEN1YmVUb0dyaWQoY29uc3QgQ3ViZSYgQywgY29uc3QgR3JpZCBHKSB7CglHcmlkIFIgPSBNYWtlR3JpZCgpOwoJZm9yIChzdGQ6OnNpemVfdCBpID0gMDsgaSA8IEcuc2l6ZSgpOyBpKyspIHsKCQlmb3IgKHN0ZDo6c2l6ZV90IGogPSAwOyBqIDwgR1tpXS5zaXplKCk7IGorKykgewoJCQlSW2ldW2pdID0gQ1tpXVtqXVtHW2ldW2pdXTsKCQl9Cgl9CglyZXR1cm4gUjsKfQpHcmlkIEN1YmVUb1Byb2JsZW0oY29uc3QgQ3ViZSYgQykgewoJR3JpZCBHID0gTWFrZUdyaWQoKTsKCWZvciAoc3RkOjpzaXplX3QgaSA9IDA7IGkgPCBHLnNpemUoKTsgaSsrKSB7CgkJZm9yIChzdGQ6OnNpemVfdCBqID0gMDsgaiA8IEdbaV0uc2l6ZSgpOyBqKyspIHsKCQkJaWYgKENbaV1bal0uc2l6ZSgpID09IDEpIHsKCQkJCUdbaV1bal0gPSBDW2ldW2pdWzBdOwoJCQl9CgkJCWVsc2UgewoJCQkJR1tpXVtqXSA9IDA7CgkJCX0KCQl9Cgl9CglyZXR1cm4gRzsKfQoKYm9vbCBTaG93TGlzdChDdWJlJiBDKSB7CglzdGQ6OnNpemVfdCBpID0gMTsKCWRvdWJsZSBEID0gMDsKCWZvciAoYXV0byYgb29vIDogQykgewoJCWZvciAoYXV0byYgb28gOiBvb28pIHsKCQkJc3RkOjpjb3V0IDw8ICdbJyA8PCBpIDw8ICc6JzsKCQkJaSsrOwoJCQlEICs9IG9vLnNpemUoKTsKCQkJZm9yIChhdXRvJiBvIDogb28pIHsKCQkJCXN0ZDo6Y291dCA8PCBvIDw8ICcsJzsKCQkJfQoJCQlzdGQ6OmNvdXQgPDwgJ10nOwoJCX0KCQlzdGQ6OmNvdXQgPDwgc3RkOjplbmRsOwoJfQoJc3RkOjpjb3V0IDw8IEQgLyA4MS4wIDw8IHN0ZDo6ZW5kbDsKCXJldHVybiB0cnVlOwp9Cgpib29sIFNob3coY29uc3QgR3JpZCYgRykgewoJZm9yIChhdXRvJiBvbyA6IEcpIHsKCQlmb3IgKGF1dG8mIG8gOiBvbykgewoJCQlzdGQ6OmNvdXQgPDwgbzsKCQl9CgkJc3RkOjpjb3V0IDw8IHN0ZDo6ZW5kbDsKCX0KCXN0ZDo6Y291dCA8PCBzdGQ6OmVuZGw7CglzdGQ6OmNvdXQgPDwgc3RkOjplbmRsOwoJcmV0dXJuIHRydWU7Cn0KRFR5cGUgR2V0QW50aUludGVyc2VjdGlvbihEVHlwZSBBICxjb25zdCBEVHlwZSYgQil7Ly/nqY3pm4blkIjjgpLlj5bjgorpmaTjgY/vvJ/vvJ8KCWZvciAoYXV0byYgbyA6IEIpIHsKCQlhdXRvIGl0ID0gc3RkOjpmaW5kKEEuYmVnaW4oKSwgQS5lbmQoKSwgbyk7CgkJaWYoaXQgIT0gQS5lbmQoKSlBLmVyYXNlKGl0KTsKCX0KCXJldHVybiBBOwp9CmJvb2wgSXNIb3Jpem9uVmFsaWQoY29uc3QgR3JpZCYgRyxzdGQ6OnNpemVfdCBWKSB7Ly/mqKrmlrnlkJHmpJzmn7sKCURUeXBlIEQ7Cglmb3IgKHN0ZDo6c2l6ZV90IGkgPSAwOyBpIDwgR1tWXS5zaXplKCk7IGkrKykgewoJCWlmKEdbVl1baV0hPTApRC5wdXNoX2JhY2soR1tWXVtpXSk7Cgl9CglzdGQ6OnNvcnQoRC5iZWdpbigpLCBELmVuZCgpKTsKCUQuZXJhc2Uoc3RkOjp1bmlxdWUoRC5iZWdpbigpLCBELmVuZCgpKSwgRC5lbmQoKSk7CglyZXR1cm4gRC5zaXplKCkgPT0gOSA/IHRydWUgOiBmYWxzZTsKfQpEVHlwZSBHZXRIb3Jpem9uVXNpbmcoY29uc3QgR3JpZCYgRyxzdGQ6OnNpemVfdCBWKSB7Ly/mqKrmlrnlkJHmpJzmn7sKCURUeXBlIEQ7Cglmb3IgKHN0ZDo6c2l6ZV90IGkgPSAwOyBpIDwgR1tWXS5zaXplKCk7IGkrKykgewoJCWlmKEdbVl1baV0hPTApIEQucHVzaF9iYWNrKEdbVl1baV0pOwoJfQoJcmV0dXJuICBEOwp9CmJvb2wgSGF2ZUhvcml6b25aZXJvKGNvbnN0IEdyaWQmIEcsc3RkOjpzaXplX3QgVikgey8v5qiq5pa55ZCR5qSc5p+7CglEVHlwZSBEOwoJZm9yIChzdGQ6OnNpemVfdCBpID0gMDsgaSA8IEdbVl0uc2l6ZSgpOyBpKyspIHsKCQlpZiAoR1tWXVtpXSA9PSAwKXJldHVybiB0cnVlOwoJfQoJcmV0dXJuIGZhbHNlOwp9CmJvb2wgSXNWZXJ0aWNhbFZhbGlkKGNvbnN0IEdyaWQmIEcsc3RkOjpzaXplX3QgSCkgey8v57im5pa55ZCR5qSc5p+7CglEVHlwZSBEOwoJZm9yIChzdGQ6OnNpemVfdCBpID0gMDsgaSA8IEcuc2l6ZSgpOyBpKyspIHsKCQlpZihHW2ldW0hdIT0gMClELnB1c2hfYmFjayhHW2ldW0hdKTsKCX0KCXN0ZDo6c29ydChELmJlZ2luKCksIEQuZW5kKCkpOwoJRC5lcmFzZShzdGQ6OnVuaXF1ZShELmJlZ2luKCksIEQuZW5kKCkpLCBELmVuZCgpKTsKCXJldHVybiBELnNpemUoKSA9PSA5ID8gdHJ1ZSA6IGZhbHNlOwp9RFR5cGUgR2V0VmVydGljYWxVc2luZyhjb25zdCBHcmlkJiBHLHN0ZDo6c2l6ZV90IEgpIHsvL+aoquaWueWQkeaknOafuwoJRFR5cGUgRDsKCURUeXBlIFR7IDAsMSwyLDMsNCw1LDYsNyw4IH07Cglmb3IgKHN0ZDo6c2l6ZV90IGkgPSAwOyBpIDwgRy5zaXplKCk7IGkrKykgewoJCWlmKEdbaV1bSF0hPSAwKUQucHVzaF9iYWNrKEdbaV1bSF0pOwoJfQoKCXJldHVybiAgRDsKfQpib29sIEhhdmVWZXJ0aWNhbFplcm8oY29uc3QgR3JpZCYgRyxzdGQ6OnNpemVfdCBIKSB7Ly/nuKbmlrnlkJHmpJzmn7sKCURUeXBlIEQ7Cglmb3IgKHN0ZDo6c2l6ZV90IGkgPSAwOyBpIDwgRy5zaXplKCk7IGkrKykgewoJCWlmIChHW2ldW0hdID09IDApcmV0dXJuIHRydWU7Cgl9CglyZXR1cm4gZmFsc2U7Cn0KYm9vbCBJc0Jsb2NrVmFsaWQoY29uc3QgR3JpZCYgRywgc3RkOjpzaXplX3QgWCwgc3RkOjpzaXplX3QgWSkgey8vM3gz5qSc5p+7CglEVHlwZSBEOwoJZm9yIChzdGQ6OnNpemVfdCBpID0gMDsgaSA8IDM7IGkrKykgewoJCWZvciAoc3RkOjpzaXplX3QgaiA9IDA7IGogPCAzOyBqKyspIHsKCQkJaWYoR1tZKjMraV1bWCozK2pdICE9MClELnB1c2hfYmFjayhHW1kqMytpXVtYKjMral0pOwoJCX0KCX0KCXN0ZDo6c29ydChELmJlZ2luKCksIEQuZW5kKCkpOwoJRC5lcmFzZShzdGQ6OnVuaXF1ZShELmJlZ2luKCksIEQuZW5kKCkpLCBELmVuZCgpKTsKCXJldHVybiBELnNpemUoKSA9PSA5ID8gdHJ1ZSA6IGZhbHNlOwp9CkRUeXBlIEdldEJsb2NrVXNpbmcoY29uc3QgR3JpZCYgRyxzdGQ6OnNpemVfdCBYLHN0ZDo6c2l6ZV90IFkpIHsvL+aoquaWueWQkeaknOafuwoJRFR5cGUgRDsKCWZvciAoc3RkOjpzaXplX3QgaSA9IDA7IGkgPCAzOyBpKyspIHsKCQlmb3IgKHN0ZDo6c2l6ZV90IGogPSAwOyBqIDwgMzsgaisrKSB7CgkJCWlmKEdbWSozK2ldW1gqMytqXSAhPTApIEQucHVzaF9iYWNrKEdbWSozK2ldW1gqMytqXSk7CgkJfQoJfQoKCXJldHVybiBEOwp9CmJvb2wgSGF2ZUJsb2NrTnVtYmVyKGNvbnN0IEdyaWQmIEcsIHN0ZDo6c2l6ZV90IFgsIHN0ZDo6c2l6ZV90IFksIHN0ZDo6c2l6ZV90IE4pIHsvL+aoquaWueWQkeaknOafuwoJRFR5cGUgRDsKCWZvciAoc3RkOjpzaXplX3QgaSA9IDA7IGkgPCAzOyBpKyspIHsKCQlmb3IgKHN0ZDo6c2l6ZV90IGogPSAwOyBqIDwgMzsgaisrKSB7CgkJCWlmIChHW1kgKiAzICsgaV1bWCAqIDMgKyBqXSA9PSBOKXJldHVybiB0cnVlOwoJCX0KCX0KCglyZXR1cm4gZmFsc2U7Cn0KYm9vbCBIYXZlQmxvY2taZXJvKGNvbnN0IEdyaWQmIEcsIHN0ZDo6c2l6ZV90IFgsIHN0ZDo6c2l6ZV90IFkpIHsvLzN4M+aknOafuwoJRFR5cGUgRDsKCWZvciAoc3RkOjpzaXplX3QgaSA9IDA7IGkgPCAzOyBpKyspIHsKCQlmb3IgKHN0ZDo6c2l6ZV90IGogPSAwOyBqIDwgMzsgaisrKSB7CgkJCWlmIChHW1kgKiAzICsgaV1bWCAqIDMgKyBqXSA9PSAwKXJldHVybiB0cnVlOwoJCX0KCX0KCglyZXR1cm4gZmFsc2U7Cn0KCgpib29sIFNlYXJjaF9yKEdyaWQmIEcsIGludCBEZWVwLCBSVHlwZSYgUiwgc3RkOjpzaXplX3QmIEMpIHsKCUMrKzsKCWdvdG94eSgxMSwgMCk7Ci8vCXN0ZDo6Y291dCA8PCBDIDw8IHN0ZDo6ZW5kbDsKCWlmIChEZWVwID49IDgxKSB7CgkJZ290b3h5KDAsIDApOwoJCS8vU2hvdyhHKTsKCQlpZiAoSXNBbnN3ZXIoRykpIHsKCQkJUi5wdXNoX2JhY2soRyk7CgkJCXN0ZDo6Y291dCA8PCAiZmluZCEhIiA8PCBzdGQ6OmVuZGw7CgkJCXJldHVybiB0cnVlOwoJCX0KCgkJcmV0dXJuIGZhbHNlOwoJfQkKCQoJc3RhdGljIGNvbnN0IERUeXBlIFR7IDEsMiwzLDQsNSw2LDcsOCw5IH07CglzdGQ6OnNpemVfdCBNWCA9IChEZWVwICUgOSkgJSAzOwoJc3RkOjpzaXplX3QgTVkgPSAoRGVlcCAlIDkpIC8gMzsKCXN0ZDo6c2l6ZV90IEJYID0gKERlZXAgLyA5KSAlIDM7CglzdGQ6OnNpemVfdCBCWSA9IChEZWVwIC8gOSkgLyAzOwoJYXV0byBCVSA9IEdldEJsb2NrVXNpbmcoRywgQlgsIEJZKTsKCWF1dG8gSFUgPSBHZXRIb3Jpem9uVXNpbmcoRywgQlkqMytNWSk7CglhdXRvIFZVID0gR2V0VmVydGljYWxVc2luZyhHLCBCWCozICsgTVgpOwoJRFR5cGUgQUk7CgkKCWlmIChHW0JZKjMgKyBNWV1bQlgqMyArIE1YXSAhPSAwKSB7CgkJcmV0dXJuIFNlYXJjaF9yKEcsIERlZXAgKyAxLCBSLEMpOwoJfQoJCglzdGQ6OmNvcHkoQlUuYmVnaW4oKSwgQlUuZW5kKCksIHN0ZDo6YmFja19pbnNlcnRlcihBSSkpOwoJc3RkOjpjb3B5KEhVLmJlZ2luKCksIEhVLmVuZCgpLCBzdGQ6OmJhY2tfaW5zZXJ0ZXIoQUkpKTsKCXN0ZDo6Y29weShWVS5iZWdpbigpLCBWVS5lbmQoKSwgc3RkOjpiYWNrX2luc2VydGVyKEFJKSk7CglzdGQ6OnNvcnQoQUkuYmVnaW4oKSwgQUkuZW5kKCkpOwoJQUkuZXJhc2Uoc3RkOjp1bmlxdWUoQUkuYmVnaW4oKSwgQUkuZW5kKCkpLCBBSS5lbmQoKSk7CglEVHlwZSBEID0gR2V0QW50aUludGVyc2VjdGlvbihULCBBSSk7CgoJYXV0byBXRyA9IEc7CglpZiAoRC5zaXplKCkgPT0gMCkgcmV0dXJuIGZhbHNlOwoJZm9yIChzdGQ6OnNpemVfdCBpID0gMDsgaSA8IEQuc2l6ZSgpOyBpKyspIHsKCQlXR1tCWSozICsgTVldW0JYKjMgKyBNWF0gPSBEW2ldOwoJCWdvdG94eSgwLCAwKTsKLy8JCVNob3coV0cpOwoJCVNlYXJjaF9yKFdHLCBEZWVwICsgMSwgUixDKTsKCX0KCglyZXR1cm4gZmFsc2U7Cgp9CmJvb2wgU2VhcmNoKEdyaWQmIEcsIFJUeXBlJiBSKSB7CglpbnQgRGVlcCA9IDA7CglzdGQ6OnNpemVfdCBDPTA7CglyZXR1cm4gU2VhcmNoX3IoRywgRGVlcCwgUiwgQyk7Cn0KCgpSVHlwZSBNYWtlSG9nZShHcmlkIEcpIHsKCUN1YmUgQ3UgPSBNYWtlQ3ViZSgpOwoJQ3ViZSBDID0gUmVkdWNlQ3ViZShDdSwgRyk7CglHcmlkIFYgPSBNYWtlR3JpZCgpOwoJUlR5cGUgUjsKCUdyaWQgQiA9IEc7CglHcmlkIEQ7CglzdGQ6OnVpbnQ2NF90IENvID0gMDsKCXN0ZDo6dWludDY0X3QgRmluZCA9IDE7CglkbyB7CgkJRCA9IEI7CgkJQiA9IEN1YmVUb1Byb2JsZW0oQyk7CgkJQyA9IFJlZHVjZUN1YmUoQywgQik7Cgl9IHdoaWxlIChEICE9IEIpOwoJZ290b3h5KDAsIDExKTsKLy8JU2hvdyhCKTsKLy8JU2hvd0xpc3QoQyk7CglhdXRvIEEgPSBDdWJlVG9Qcm9ibGVtKEMpOwoJZ290b3h5KDAsIDExKTsKLy8JU2hvdyhBKTsKCVNlYXJjaChBLCBSKTsKCglyZXR1cm4gUjsKfQoKaW50IG1haW4oKSB7CglHcmlkIEcgPSBNYWtlUHJvYmxlbSgpOwoJUlR5cGUgUjsKCVNob3coRyk7CglSID0gTWFrZUhvZ2UoRyk7Cglmb3IgKGF1dG8mIG8gOiBSKSB7CgkJZ290b3h5KDAsIDApOwoJCVNob3cobyk7Cgl9CgoJcmV0dXJuIDA7Cn0=