#include #include #include #include #include using namespace std; /* Dinic maxflow with unit capacities O(min(V^2/3, E^1/2)E) or O(sqrt(V) * E) on bipartite matching graphs. */ template class maxflow_dinic { public: explicit maxflow_dinic(int N) : N(N), edge_lst(N) { } void add_edge(int u, int v, flow_t capuv, flow_t capvu) { edge_lst[u].push_back(edges.size()); edge_lst[v].push_back(edges.size()); edge_map[make_pair(u, v)] = edges.size(); edges.push_back(make_pair(make_pair(u, v), make_pair(capuv, capvu))); } flow_t compute(int s, int t) { vector dist(N); vector vis(N); for(flow_t fl = 0; ; ) { fill(dist.begin(), dist.end(), -1); fill(vis.begin(), vis.end(), 0UL); dist[s] = 0; vis[s] = edge_lst[s].size(); queue q; q.push(s); while(!q.empty()) { int u = q.front(); q.pop(); for(size_t i = 0; i < edge_lst[u].size(); i++) { int j = edge_lst[u][i]; pair vert = edges[j].first; if((vert.first == u ? edges[j].second.first : edges[j].second.second) > 0) { int v = vert.first + vert.second - u; if(!vis[v]) { vis[v] = edge_lst[v].size(); dist[v] = dist[u] + 1; q.push(v); } } } } if(!vis[t]) { return fl; } fill(vis.begin(), vis.end(), 0); fl += dfs(s, t, 0, dist, vis); } } flow_t flow(int u, int v) { __typeof__(edge_map.begin()) it = edge_map.find(make_pair(u, v)); if(it == edge_map.end()) return 0; int eid = it->second; return edges[eid].second.second; } flow_t dfs(int u, int t, flow_t cp, vector& dist, vector& vis) { if(u == t) return cp; flow_t fl = 0; for(size_t& i = vis[u]; i < edge_lst[u].size(); i++) { int j = edge_lst[u][i]; pair vert = edges[j].first; int v = vert.first + vert.second - u; if(dist[u] + 1 != dist[v]) continue; flow_t ecp = vert.first == u ? edges[j].second.first : edges[j].second.second; if(ecp == 0) continue; if(cp) ecp = min(ecp, cp); ecp = dfs(v, t, ecp, dist, vis); fl += ecp; (vert.first == u ? edges[j].second.first : edges[j].second.second) -= ecp; (vert.first == u ? edges[j].second.second : edges[j].second.first) += ecp; if(cp != 0 && ecp == cp) break; if(cp) cp -= ecp; } return fl; } int N; vector, pair > > edges; vector > edge_lst; map, int> edge_map; }; int dr[] = {1, 0, -1, 0}; int dc[] = {0, 1, 0, -1}; /* Calculates the set of nodes connected to src that could increase the flow to snk if their flow was increased. */ vector push_set(maxflow_dinic& mf, int src, int snk, bool rev) { queue q; q.push(snk); vector result; vector vis(mf.N); while (!q.empty()) { int u = q.front(); q.pop(); for (int i : mf.edge_lst[u]) { pair vert = mf.edges[i].first; int v = vert.first + vert.second - u; if (v == src) { result.push_back(u); } else if (!vis[v]) { if (((vert.first != u) ^ rev) ? mf.edges[i].second.first : mf.edges[i].second.second) { vis[v] = true; q.push(v); } } } } return result; } int main() { int R, C; cin >> R >> C; vector A(R); for (int i = 0; i < R; i++) { cin >> A[i]; } int src = R * C; int snk = src + 1; maxflow_dinic mf(snk + 1); for (int r = 0; r < R; r++) { for (int c = 0; c < C; c++) { if (A[r][c] == '#') continue; if ((r + c) % 2 == 1) { mf.add_edge(r * C + c, snk, 1, 0); } else { mf.add_edge(src, r * C + c, 1, 0); for (int i = 0; i < 4; i++) { int nr = r + dr[i]; int nc = c + dc[i]; if (nr < 0 || nc < 0 || nr >= R || nc >= C || A[nr][nc] == '#' || A[r][c] == A[nr][nc]) { continue; } mf.add_edge(r * C + c, nr * C + nc, 1, 0); } } } } cout << mf.compute(src, snk) << endl; vector needed(R * C, false); for (int i : push_set(mf, src, snk, false)) { needed[i] = true; } for (int i : push_set(mf, snk, src, true)) { needed[i] = true; } vector ok(26, false); for (int r = 0; r < R; r++) { for (int c = 0; c < C; c++) { if (A[r][c] != '#' && !needed[r * C + c]) { ok[A[r][c] - 'a'] = true; } } } for (int i = 0; i < 26; i++) { if (ok[i]) { cout << (char)('a' + i); } } cout << endl; return 0; }