#include #include #include #include #include using namespace std; #include class Timer{ protected: double startTime; double limit; bool alreadyTimeup; public: Timer(double time_limit){ set(time_limit); } void set(double time_limit){ limit = time_limit; startTime = now(); alreadyTimeup = false; } bool timeup(){ if(alreadyTimeup) return true; if(now() - startTime > limit){ alreadyTimeup = true; return true; }else{ return false; } } double elapse(){ return now() - startTime; } double used(){ return elapse() / limit; } protected: double now(){ timeval tv; gettimeofday(&tv, 0); return tv.tv_sec + tv.tv_usec * 1e-6; } }; #include #include template struct PointBase{ T y, x; PointBase(T y_, T x_):y(y_),x(x_){} PointBase(){} bool operator<(const PointBase& op) const{ if(this->y == op.y) return this->x < op.x; return this->y < op.y; } bool operator==(const PointBase& op) const{ return this->y == op.y && this->x == op.x; } PointBase& operator+=(const PointBase& op){ this->y += op.y; this->x += op.x; return *this; } }; template string to_string(const PointBase& p){ return string("(") + to_string(p.y) + "," + to_string(p.x) + ")"; } template std::ostream& operator<<(std::ostream& os, const PointBase& p) { os << to_string(p); return os; } typedef PointBase Point; template struct BoardBase{ int h, w; vector data; BoardBase(int h_, int w_, const T& init):h(h_),w(w_),data(h * w, init){} void put(Point& p, const T& val){ data[p.y*w + p.x] = val; } void put(int pos, const T& val){ data[pos] = val; } void put(int y, int x, const T& val){ data[y*w + x] = val; } T& get(Point& p){ return data[p.y*w + p.x]; } T& get(int pos){ return data[pos]; } T& get(int y, int x){ return data[y*w + x]; } }; typedef BoardBase Board; typedef long long LL; //* mt19937 randint(123123123); /*/ struct XORShift{ uint32_t operator()(){ static uint32_t x = 123456789, y = 362436069, z = 521288629, w = 88675123; uint32_t t = x ^ (x << 11); x = y; y = z; z = w; return w = (w ^ (w >> 19)) ^ (t ^ (t >> 8)); } } randint; //*/ const int N = 60, K = 500; vector L; Timer timer(0.9); int componentCount(uint64_t val, uint64_t val_zero){ uint64_t comp = (val ^ (val<<1)) & val; uint64_t bridge = val_zero & (val >> 1) & (val << 1); return __builtin_popcountll(comp) - __builtin_popcountll(bridge); } int componentCount(vector& vec, vector& vec_zero){ int ans = 0; for(int i = 0; i < N; ++i){ ans += componentCount(vec[i], vec_zero[i]); } return ans; } int componentCount(vector& rows, vector& cols, vector& rows_zero, vector& cols_zero){ return componentCount(rows, rows_zero) + componentCount(cols, cols_zero); } int componentCountDiff(vector& rows, vector& cols, vector& rows_zero, vector& cols_zero, int y, int x){ return componentCount(rows[y], rows_zero[y]) + componentCount(cols[x], cols_zero[x]); } struct State{ vector rows; vector cols; vector assign; vector assign_row; int score; int last_cur; Point last_p; bool last_is_row; State(vector& rows_, vector& cols_) :rows(rows_), cols(cols_), assign(K), assign_row(K){ score = 0; for(int i = 0; i < K; ++i){ assign[i] = Point(0, 0); assign_row[i] = true; rows[0] ^= (1ULL << (0+L[i])) - (1ULL << 0); score += __builtin_popcountll(rows[i]); score += __builtin_popcountll(cols[i]); } } void place(int cur, int y, int x, int is_row){ // undo info last_cur = cur; last_p = assign[cur]; last_is_row = assign_row[cur]; // unplace Point p = assign[cur]; if(assign_row[cur]){ score -= __builtin_popcountll(rows[p.y]); rows[p.y] ^= (1ULL << (p.x+L[cur])) - (1ULL << p.x); score += __builtin_popcountll(rows[p.y]); }else{ score -= __builtin_popcountll(cols[p.x]); cols[p.x] ^= (1ULL << (p.y+L[cur])) - (1ULL << p.y); score += __builtin_popcountll(cols[p.x]); } // place if(is_row){ assign[cur] = Point(y, x); assign_row[cur] = true; score -= __builtin_popcountll(rows[y]); rows[y] ^= (1ULL << (x+L[cur])) - (1ULL << x); score += __builtin_popcountll(rows[y]); }else{ assign[cur] = Point(y, x); assign_row[cur] = false; score -= __builtin_popcountll(cols[x]); cols[x] ^= (1ULL << (y+L[cur])) - (1ULL << y); score += __builtin_popcountll(cols[x]); } } void undo(){ place(last_cur, last_p.y, last_p.x, last_is_row); } vector> getAssign() const{ vector> res(K); for(int i = 0; i < K; ++i){ res[i].first = assign[i]; if(assign_row[i]){ res[i].second = Point(assign[i].y + 1, assign[i].x + L[i]); }else{ res[i].second = Point(assign[i].y + L[i], assign[i].x + 1); } } return res; } int getScore() const{ return score; } }; vector> optimize(vector& rows, vector& cols){ State s(rows, cols); State best_s = s; double threshold_base = 5.0; int threshold = threshold_base; for(LL e = 0; ; ++e){ if((e & 0xff) == 0xff){ threshold = 5.0 * (1.0 - timer.used()); if(timer.timeup()) break; } uint32_t r = randint(); bool is_row = (r & 1); int cur = (r >> 1) % N; int offset = randint() % (N+1 - L[cur]); if(is_row){ int y = randint() % N; s.place(cur, y, offset, true); }else{ int x = randint() % N; s.place(cur, offset, x, true); } if(s.getScore()-threshold <= best_s.getScore()){ if(s.getScore() < best_s.getScore()){ cerr << "update : " << best_s.getScore() << " -> " << s.getScore() << endl; best_s = s; } }else{ s.undo(); } } return best_s.getAssign(); } int calcScore(vector>& board1, vector>& board2){ int score = 0; for(int y = 0; y < N; ++ y){ for(int x = 0; x < N; ++x){ score += board1[y][x] - board2[y][x]; } } return score; } int main(){ int N_, K_; cin >> N_ >> K_; assert(N == N_ && K == K_); L.resize(K); for(int i = 0; i < K; ++i){ cin >> L[i]; } vector> board(N, vector(N)); for(int y = 0; y < N; ++y){ string s; cin >> s; for(int x = 0; x < N; ++x){ board[y][x] = (s[x] == '1')? 1: 0; } } vector rows(N), cols(N); vector rows_zero(N), cols_zero(N); vector one_index; for(int y = 0; y < N; ++y){ for(int x = 0; x < N; ++x){ if(board[y][x] == 1){ rows[y] |= (1ULL << x); one_index.emplace_back(y, x); }else{ rows_zero[y] |= (1ULL << x); cols_zero[x] |= (1ULL << y); } } } cerr << "comp cnt : " << componentCount(rows, cols, rows_zero, cols_zero) << endl; int comp_best = componentCount(rows, cols, rows_zero, cols_zero); int comp_score = comp_best; vector rows_best = rows, cols_best = cols; LL max_e = 1000*1000*5; for(LL e = 0; e < max_e; ++e){ int threshold = 5.0 * (max_e - e) / max_e; int r = randint() % one_index.size(); int y = one_index[r].y; int x = one_index[r].x; int score_prev = componentCountDiff(rows, cols, rows_zero, cols_zero, y, x); rows[y] ^= (1ULL << x); cols[x] ^= (1ULL << y); int score_next = componentCountDiff(rows, cols, rows_zero, cols_zero, y, x); //cerr << comp_best << ", " << score << ", " << score - comp_best << endl; if(comp_score + score_next - score_prev - threshold <= comp_best){ comp_score += score_next - score_prev; //assert(score == componentCount(rows, cols, rows_zero, cols_zero)); if(comp_score < comp_best){ comp_best = comp_score; cerr << comp_best << endl; } }else{ rows[y] ^= (1ULL << x); cols[x] ^= (1ULL << y); } } vector> assign = optimize(rows, cols); vector> ans_board = board; for(pair p: assign){ cout << p.first.y+1 << " " << p.first.x+1 << " " << p.second.y << " " << p.second.x << endl; for(int y = p.first.y; y < p.second.y; ++y){ for(int x = p.first.x; x < p.second.x; ++x){ ans_board[y][x] = 1 - ans_board[y][x]; } } } int score = calcScore(board, ans_board); cerr << "Score = " << score << endl; return 0; }