はまやんはまやんはまやん

hamayanhamayan's blog

しろくろチョコレート [yukicoder 421]

問題

http://yukicoder.me/problems/no/421

N行M列の板チョコが与えられる
この板チョコは黒チョコと白チョコが交互に市松模様状に並んでいる
以下のようにチョコを食べる

1. 任意の位置からチョコを1つ選んで食べる -> 幸福度1
2. 任意の位置から黒チョコと白チョコを1つずつ選んで食べる -> 幸福度10
3. 任意の位置から黒チョコと白チョコが連続している2つを選んで食べる -> 幸福度100

板チョコの構成が与えられるので、最適な食べ方での最大幸福度を求める

1 <= N,M <= 50

考察

1. まず戦略としてできるだけ3の選択肢で食べたい
2. 連続している部分をできるだけ作りたい
3. 連続しているペアをできるだけ作りたい
4. 最大マッチング問題か?
5. それでいけそうか

6. 隣接している黒チョコ・白チョコ間に辺を貼って、最大マッチング問題として解く
7. 辺を貼るときは、→と↓だけ見るようにして頂点を全て走査すると、かぶらず辺が掛けられる
8. あとは以下の式で計算するだけ

黒チョコb個、白チョコw個、最大マッチング数をmとすると
幸福度100 -> m回
幸福度10 -> min(b - m, w - m)回
幸福度1 -> abs(b - w)回

実装

http://yukicoder.me/submissions/116403

#define INF INT_MAX/2
struct Maxflow {
	struct edge { int to, cap, rev; edge(int t, int c, int r) { to = t; cap = c; rev = r; } };
	int V;
	vector<vector<edge>> G;
	vector<int> itr, level;

	Maxflow(int V) : V(V) { G.assign(V, vector<edge>()); }

	void add_edge(int from, int to, int cap) {
		G[from].push_back(edge(to, cap, (int)G[to].size()));
		G[to].push_back(edge(from, 0, (int)G[from].size() - 1));
	}

	void bfs(int s) {
		level.assign(V, -1);
		queue<int> q;
		level[s] = 0; q.push(s);
		while (!q.empty()) {
			int v = q.front(); q.pop();
			for (auto &e : G[v]) {
				if (e.cap > 0 and level[e.to] < 0) {
					level[e.to] = level[v] + 1;
					q.push(e.to);
				}
			}
		}
	}

	int dfs(int v, int t, int f) {
		if (v == t) return f;
		for (int& i = itr[v]; i < (int)G[v].size(); ++i) {
			edge& e = G[v][i];
			if (e.cap > 0 and level[v] < level[e.to]) {
				int d = dfs(e.to, t, min(f, e.cap));
				if (d > 0) {
					e.cap -= d;
					G[e.to][e.rev].cap += d;
					return d;
				}
			}
		}
		return 0;
	}

	int run(int s, int t) {
		int ret = 0, f;
		while (bfs(s), level[t] >= 0) {
			itr.assign(V, 0);
			while ((f = dfs(s, t, INF)) > 0) ret += f;
		}
		return ret;
	}
};
//-----------------------------------------------------------------
int N, M;
string S[50];
int idx[50][50];
int dx[2] = { 1, 0 };
int dy[2] = { 0, 1 };
//-----------------------------------------------------------------
int main() {
	cin >> N >> M;
	rep(i, 0, N) cin >> S[i];

	int b = 0, w = 0;
	rep(y, 0, N) rep(x, 0, M) {
		if (S[y][x] == 'w')
			idx[y][x] = w, w++;
		else if (S[y][x] == 'b')
			idx[y][x] = b, b++;
	}

	Maxflow mf(1 + w + b + 1);
	rep(i, 0, w) mf.add_edge(0, i + 1, 1);
	rep(y, 0, N) rep(x, 0, M) if(S[y][x] != '.') rep(i, 0, 2) {
		int yy = y + dy[i];
		int xx = x + dx[i];
		if (yy < 0 || N <= yy) continue;
		if (xx < 0 || M <= xx) continue;
		if (S[yy][xx] == '.') continue;

		int bb = (S[y][x] == 'b' ? idx[y][x] : idx[yy][xx]);
		int ww = (S[y][x] == 'b' ? idx[yy][xx] : idx[y][x]);
		mf.add_edge(ww + 1, bb + 1 + w, 1);
	}
	rep(i, 0, b) mf.add_edge(1 + w + i, 1 + w + b, 1);

	int m = mf.run(0, 1 + w + b);

	int ans = 0;
	ans += m * 100;
	ans += min(b - m, w - m) * 10;
	ans += abs(b - w);

	cout << ans << endl;
}