#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace std; static const double EPS = 1e-8; static const double PI = 4.0 * atan(1.0); static const double PI2 = 8.0 * atan(1.0); typedef long long ll; #define ALL(c) (c).begin(), (c).end() #define CLEAR(v) memset(v,0,sizeof(v)) #define MP(a,b) make_pair((a),(b)) #define REP(i,n) for(int i=0;i<(int)n;++i) #define ABS(a) ((a)>0?(a):-(a)) static const int R = 4; static const int C = 4; static const int kMaxDepth = 5; static const int kClearState = 5; bool isEnd(int field[R][C]) { REP(r, R) { REP(c, C) { if (field[r][c] != 0) { return false; } } } return true; } static const int dr[] = {0, 0, 1, -1}; static const int dc[] = {1, -1, 0, 0}; struct Bubble { int r, c, dir; bool alive; Bubble(int r, int c, int dir) : r(r), c(c), dir(dir), alive(true) { } static void step(Bubble& rh) { rh.r += dr[rh.dir]; rh.c += dc[rh.dir]; } static bool isDead(const Bubble& rh) { return !rh.alive; } static bool isOut(const Bubble& rh) { return rh.r < 0 || R <= rh.r || rh.c < 0 || C <= rh.c; } }; void advance(int field[R][C]) { vector bubbles; do { // 小さな泡を進める for_each(ALL(bubbles), Bubble::step); // 壁にぶつかった小さな泡を取り除く bubbles.erase(remove_if(ALL(bubbles), Bubble::isOut), bubbles.end()); // 小さな泡を他のセルに吸収させる REP(i, bubbles.size()) { Bubble& b = bubbles[i]; if (field[b.r][b.c]) { ++field[b.r][b.c]; b.alive = false; } } // 吸収された小さな泡を取り除く bubbles.erase(remove_if(ALL(bubbles), Bubble::isDead), bubbles.end()); // 破裂した泡を小さな泡に変換 REP(r, R) { REP(c, C) { if (field[r][c] >= kClearState) { field[r][c] = 0; REP(dir, 4) { bubbles.push_back(Bubble(r, c, dir)); } } } } } while (!bubbles.empty()); } ll makeHash(int field[R][C]) { ll hash = 0; int index = 0; REP(r, R) { REP(c, C) { hash |= (((ll)field[r][c]) << (index++ * 3)); } } return hash; } int bestDepth = kMaxDepth + 1; map memo; int dfs(int prevField[R][C], int depth) { if (bestDepth <= depth) { return INT_MAX / 2; } const ll hash = makeHash(prevField); int& res = memo[hash]; if (res == 0) { res = INT_MAX / 2; REP(clickR, R) { REP(clickC, C) { int field[R][C]; memcpy(field, prevField, sizeof(field)); ++field[clickR][clickC]; advance(field); if (isEnd(field)) { bestDepth = depth; res = 0; clickR = R; clickC = C; continue; } res = min(res, dfs(field, depth + 1)); } } ++res; } return res; } int main() { int field[R][C]; REP(r, R) { REP(c, C) { cin >> field[r][c]; } } if (isEnd(field)) { cout << 0 << endl; return 0; } int answer = dfs(field, 1); if (answer >= INT_MAX / 2) { answer = -1; } cout << answer << endl; }