結果

問題 No.1479 Matrix Eraser
ユーザー startcppstartcpp
提出日時 2021-04-16 21:55:18
言語 C++14
(gcc 12.3.0 + boost 1.83.0)
結果
AC  
実行時間 605 ms / 3,000 ms
コード長 7,823 bytes
コンパイル時間 1,880 ms
コンパイル使用メモリ 132,780 KB
実行使用メモリ 59,008 KB
最終ジャッジ日時 2024-07-03 01:36:56
合計ジャッジ時間 13,521 ms
ジャッジサーバーID
(参考情報)
judge2 / judge1
このコードへのチャレンジ
(要ログイン)

テストケース

テストケース表示
入力 結果 実行時間
実行使用メモリ
testcase_00 AC 2 ms
5,248 KB
testcase_01 AC 2 ms
5,376 KB
testcase_02 AC 2 ms
5,376 KB
testcase_03 AC 2 ms
5,376 KB
testcase_04 AC 2 ms
5,376 KB
testcase_05 AC 2 ms
5,376 KB
testcase_06 AC 2 ms
5,376 KB
testcase_07 AC 143 ms
41,344 KB
testcase_08 AC 176 ms
43,264 KB
testcase_09 AC 287 ms
48,384 KB
testcase_10 AC 494 ms
55,936 KB
testcase_11 AC 333 ms
50,048 KB
testcase_12 AC 155 ms
42,112 KB
testcase_13 AC 179 ms
43,392 KB
testcase_14 AC 160 ms
42,368 KB
testcase_15 AC 105 ms
39,296 KB
testcase_16 AC 167 ms
42,752 KB
testcase_17 AC 586 ms
59,008 KB
testcase_18 AC 585 ms
59,008 KB
testcase_19 AC 588 ms
59,008 KB
testcase_20 AC 594 ms
59,008 KB
testcase_21 AC 591 ms
58,880 KB
testcase_22 AC 592 ms
58,880 KB
testcase_23 AC 582 ms
58,880 KB
testcase_24 AC 598 ms
58,880 KB
testcase_25 AC 593 ms
59,008 KB
testcase_26 AC 605 ms
59,008 KB
testcase_27 AC 162 ms
11,392 KB
testcase_28 AC 162 ms
11,392 KB
testcase_29 AC 164 ms
11,392 KB
testcase_30 AC 163 ms
11,392 KB
testcase_31 AC 164 ms
11,264 KB
testcase_32 AC 95 ms
14,720 KB
testcase_33 AC 96 ms
14,732 KB
testcase_34 AC 96 ms
14,624 KB
testcase_35 AC 95 ms
14,604 KB
testcase_36 AC 95 ms
14,628 KB
testcase_37 AC 61 ms
9,880 KB
testcase_38 AC 179 ms
9,600 KB
testcase_39 AC 435 ms
46,208 KB
testcase_40 AC 2 ms
5,376 KB
権限があれば一括ダウンロードができます

ソースコード

diff #

#include <iostream>
#include <vector>
#include <set>
#include <map>
#include <random>
#include <vector>

#include <algorithm>

#include <vector>

namespace atcoder {

namespace internal {

template <class T> struct simple_queue {
    std::vector<T> payload;
    int pos = 0;
    void reserve(int n) { payload.reserve(n); }
    int size() const { return int(payload.size()) - pos; }
    bool empty() const { return pos == int(payload.size()); }
    void push(const T& t) { payload.push_back(t); }
    T& front() { return payload[pos]; }
    void clear() {
        payload.clear();
        pos = 0;
    }
    void pop() { pos++; }
};

}  // namespace internal

}  // namespace atcoder

#include <cassert>
#include <limits>
#include <queue>
#include <vector>

namespace atcoder {

template <class Cap> struct mf_graph {
  public:
    mf_graph() : _n(0) {}
    mf_graph(int n) : _n(n), g(n) {}

    int add_edge(int from, int to, Cap cap) {
        assert(0 <= from && from < _n);
        assert(0 <= to && to < _n);
        assert(0 <= cap);
        int m = int(pos.size());
        pos.push_back({from, int(g[from].size())});
        g[from].push_back(_edge{to, int(g[to].size()), cap});
        g[to].push_back(_edge{from, int(g[from].size()) - 1, 0});
        return m;
    }

    struct edge {
        int from, to;
        Cap cap, flow;
    };

    edge get_edge(int i) {
        int m = int(pos.size());
        assert(0 <= i && i < m);
        auto _e = g[pos[i].first][pos[i].second];
        auto _re = g[_e.to][_e.rev];
        return edge{pos[i].first, _e.to, _e.cap + _re.cap, _re.cap};
    }
    std::vector<edge> edges() {
        int m = int(pos.size());
        std::vector<edge> result;
        for (int i = 0; i < m; i++) {
            result.push_back(get_edge(i));
        }
        return result;
    }
    void change_edge(int i, Cap new_cap, Cap new_flow) {
        int m = int(pos.size());
        assert(0 <= i && i < m);
        assert(0 <= new_flow && new_flow <= new_cap);
        auto& _e = g[pos[i].first][pos[i].second];
        auto& _re = g[_e.to][_e.rev];
        _e.cap = new_cap - new_flow;
        _re.cap = new_flow;
    }

    Cap flow(int s, int t) {
        return flow(s, t, std::numeric_limits<Cap>::max());
    }
    Cap flow(int s, int t, Cap flow_limit) {
        assert(0 <= s && s < _n);
        assert(0 <= t && t < _n);

        std::vector<int> level(_n), iter(_n);
        internal::simple_queue<int> que;

        auto bfs = [&]() {
            std::fill(level.begin(), level.end(), -1);
            level[s] = 0;
            que.clear();
            que.push(s);
            while (!que.empty()) {
                int v = que.front();
                que.pop();
                for (auto e : g[v]) {
                    if (e.cap == 0 || level[e.to] >= 0) continue;
                    level[e.to] = level[v] + 1;
                    if (e.to == t) return;
                    que.push(e.to);
                }
            }
        };
        auto dfs = [&](auto self, int v, Cap up) {
            if (v == s) return up;
            Cap res = 0;
            int level_v = level[v];
            for (int& i = iter[v]; i < int(g[v].size()); i++) {
                _edge& e = g[v][i];
                if (level_v <= level[e.to] || g[e.to][e.rev].cap == 0) continue;
                Cap d =
                    self(self, e.to, std::min(up - res, g[e.to][e.rev].cap));
                if (d <= 0) continue;
                g[v][i].cap += d;
                g[e.to][e.rev].cap -= d;
                res += d;
                if (res == up) break;
            }
            return res;
        };

        Cap flow = 0;
        while (flow < flow_limit) {
            bfs();
            if (level[t] == -1) break;
            std::fill(iter.begin(), iter.end(), 0);
            while (flow < flow_limit) {
                Cap f = dfs(dfs, t, flow_limit - flow);
                if (!f) break;
                flow += f;
            }
        }
        return flow;
    }

    std::vector<bool> min_cut(int s) {
        std::vector<bool> visited(_n);
        internal::simple_queue<int> que;
        que.push(s);
        while (!que.empty()) {
            int p = que.front();
            que.pop();
            visited[p] = true;
            for (auto e : g[p]) {
                if (e.cap && !visited[e.to]) {
                    visited[e.to] = true;
                    que.push(e.to);
                }
            }
        }
        return visited;
    }

  private:
    int _n;
    struct _edge {
        int to, rev;
        Cap cap;
    };
    std::vector<std::pair<int, int>> pos;
    std::vector<std::vector<_edge>> g;
};

}  // namespace atcoder

#define rep(i, n) for(i = 0; i < n; i++)
using namespace std;
using namespace atcoder;

void printMat(vector<vector<int>> &a) {
	int i, j;
	rep(i, a.size()) {
		rep(j, a[i].size()) {
			cout << a[i][j];
			if (j + 1 < a[i].size()) cout << " ";
		}
		cout << endl;
	}
	cout << endl;
}

bool isAllZero(vector<vector<int>> &a) {
	int i, j;
	rep(i, a.size()) rep(j, a[i].size()) if (a[i][j] != 0) return false;
	return true;
}

map<vector<vector<int>>, int> dp;
int dfs(vector<vector<int>> &a) {
	if (isAllZero(a)) return 0;
	if (dp.find(a) != dp.end()) return dp[a];
	
	int i, j;
	int ret = 114514;
	rep(i, a.size()) {
		vector<int> backup = a[i];
		int mmax = a[i][0];
		rep(j, a[i].size()) mmax = max(mmax, a[i][j]);
		if (mmax == 0) continue;
		rep(j, a[i].size()) if (a[i][j] == mmax) a[i][j] = 0;
		int res = dfs(a) + 1;
		ret = min(ret, res);
		a[i] = backup;
	}
	
	rep(j, a[0].size()) {
		vector<int> backup(a.size());
		rep(i, a.size()) backup[i] = a[i][j];
		int mmax = a[0][j];
		rep(i, a.size()) mmax = max(mmax, a[i][j]);
		if (mmax == 0) continue;
		rep(i, a.size()) if (a[i][j] == mmax) a[i][j] = 0;
		int res = dfs(a) + 1;
		ret = min(ret, res);
		rep(i, a.size()) a[i][j] = backup[i];
	}
	return dp[a] = ret;
}

int allSearch(vector<vector<int>> a) {
	dp.clear();
	return dfs(a);
}

void to_unique(vector<int> &v) {
	sort(v.begin(), v.end());
	v.erase(unique(v.begin(), v.end()), v.end());
}

int greedy(vector<vector<int>> a) {
	int i, j;
	int maxA = 0;
	rep(i, a.size()) rep(j, a[i].size()) maxA = max(maxA, a[i][j]);
	
	typedef pair<int, int> P;
	vector<vector<P>> poses(maxA + 1);
	vector<vector<int>> rows(maxA + 1);
	vector<vector<int>> cols(maxA + 1);
	rep(i, a.size()) {
		rep(j, a[i].size()) {
			poses[a[i][j]].push_back(P(i, j));
			rows[a[i][j]].push_back(i);
			cols[a[i][j]].push_back(j);
		}
	}
	
	rep(i, maxA + 1) {
		to_unique(rows[i]);
		to_unique(cols[i]);
	}
	
	int ret = 0;
	rep(i, maxA + 1) {
		if (i == 0) continue;
		
		int n = rows[i].size();
		int m = cols[i].size();
		mf_graph<int> g(n + m + 2);
		int s = n + m;
		int t = n + m + 1;
		
		rep(j, poses[i].size()) {
			int row = poses[i][j].first;
			int col = poses[i][j].second;
			row = lower_bound(rows[i].begin(), rows[i].end(), row) - rows[i].begin();
			col = lower_bound(cols[i].begin(), cols[i].end(), col) - cols[i].begin();
			g.add_edge(row, n + col, 1);
		}
		rep(j, n) g.add_edge(s, j, 1);
		rep(j, m) g.add_edge(n + j, t, 1);
		ret += g.flow(s, t);
	}
	return ret;
}

void test() {
	int h = 4, w = 4, K = 4, T = 1000;
	mt19937 mt(252521);
	
	for (int t = 0; t < T; t++) {
		vector<vector<int>> a(h, vector<int>(w));
		int i, j;
		rep(i, h) rep(j, w) a[i][j] = mt() % K;
		int res1 = allSearch(a);
		int res2 = greedy(a);
		if (res1 != res2) {
			cout << "Wrong Answer[" << t << "]" << endl;
			printMat(a);
			cout << "all = " << res1 << endl;
			cout << "greedy = " << res2 << endl;
			return;
		}
	}
	cout << "Accepted !" << endl;
}

signed main() {
	int h, w; cin >> h >> w;
	vector<vector<int>> a(h, vector<int>(w));
	
	int i, j;
	rep(i, h) rep(j, w) cin >> a[i][j];
	cout << greedy(a) << endl;
	return 0;
}
0