#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace std; typedef long long ll; typedef vector VI; typedef pair PII; #define REP(i,s,t) for(int i=(s);i<(t);i++) #define FILL(x,v) memset(x,v,sizeof(x)) const int INF = (int)1E9; #define MAXN 11 int R, C; int minBit[1<= 0 ? g[gUp] : -1; int gDownSave = gDown >= 0 ? g[gDown] : - 1; sort(g.begin(), g.end()); empty = 0; colg = VI(C, -1); REP(i,0,g.size()) { empty |= g[i]; int v = g[i]; while (v) { colg[minBit[v]] = i; v -= 1 << minBit[v]; } if (g[i] == gUpSave) gUp = i; // normalization may change gExit if (g[i] == gDownSave) gDown = i; } } bool operator < (const Group &ano) const { if (gUp != ano.gUp) return gUp < ano.gUp; if (gDown != ano.gDown) return gDown < ano.gDown; return g < ano.g; } bool operator == (const Group &ano) const { return gUp == ano.gUp && gDown == ano.gDown && g == ano.g; } }; vector groups; int groupCount; void enumGroups(int c, VI &g, bool adjDiff, VI &col, VI &crossed) { if (c == C) { groupCount += g.size() * (1 + g.size()) * (1 + g.size()); // TEST ONLY REP(gUp,-1,(int)g.size()) REP(gExit,-1,(int)g.size()) groups.push_back(Group(g, gUp, gExit)); return; } int lastColg = c == 0 ? -1 : col[c - 1]; REP(i,0,g.size()) { // can only have at most one pair of neighboring cells belonging to different connected components if (lastColg != -1 && i != lastColg && adjDiff) continue; // skip interleaving connected components, this prunes a small number of states and is not necessary if (crossed[i]) continue; int ii = maxBit[g[i]]; REP(cc, ii + 1, c) { if (col[cc] == -1) continue; crossed[col[cc]]++; } g[i] ^= 1 << c; col[c] = i; enumGroups(c + 1, g, adjDiff || (lastColg != -1 && i != lastColg), col, crossed); // merge into an existing component col[c] = -1; g[i] ^= 1 << c; REP(cc, ii + 1, c) { if (col[cc] == -1) continue; crossed[col[cc]]--; } } if (!adjDiff || lastColg == -1) { int ng = g.size(); g.push_back(1 << c); crossed.push_back(0); col[c] = ng; enumGroups(c + 1, g, adjDiff || lastColg != -1, col, crossed); // create a new component col[c] = -1; crossed.pop_back(); g.pop_back(); } enumGroups(c + 1, g, adjDiff, col, crossed); // no new component from this column } inline bool isHallway(int k, int c) { return groups[k].empty & (1 << c); } inline int stateIndex(int c, Group grp) { int idx = lower_bound(groups.begin(), groups.end(), grp) - groups.begin(); assert (idx < groups.size() && groups[idx] == grp); return idx; } int addShop(int k, int c) { VI g = groups[k].g; int gUp = groups[k].gUp, gDown = groups[k].gDown; int i = groups[k].colg[c]; if (i != -1) { g[i] ^= 1 << c; if (g[i] == 0) { if (gUp != i || gDown != i) return -1; // cannot close a connected component without connecting it to U or D gUp = -1; gDown = -1; g.erase(g.begin() + i); } return stateIndex(c, Group(g, gUp, gDown)); } return k; } // merge component b into a, b will be removed // a will be updated to the new index, if b was before a void mergeGroup(VI &g, int &gUp, int &gDown, int &a, int &b) { g[a] |= g[b]; if (gUp == b) gUp = a; if (gDown == b) gDown = a; if (gUp > b) gUp--; if (gDown > b) gDown--; if (a > b) a--; g.erase(g.begin() + b); } int addHallway(int k, int c, int upDown = 0) { // upDown=1: up, upDown=-1: down Group &grp = groups[k]; VI g = groups[k].g; int gUp = groups[k].gUp, gDown = groups[k].gDown; int newUpDown = -1; int li = c > 0 ? grp.colg[c - 1] : -1; // left component int ti = grp.colg[c]; // top component if (ti == -1) { // top is shop if (li == -1) { // left is shop, create new hallway component g.push_back(1 << c); if (upDown) newUpDown = g.size() - 1; } else { // left is hallway, merge g[li] |= 1 << c; if (upDown) newUpDown = li; } } else { // top is hallway if (li == -1) { // left is shop, nothing changes } else { // left is hallway, connect component li to component ti if (ti != li) { // li is to be removed mergeGroup(g, gUp, gDown, ti, li); } } if (upDown) newUpDown = ti; } if (newUpDown != -1) { if (upDown == 1) gUp = newUpDown; else if (upDown == -1) gDown = newUpDown; } return stateIndex(c, Group(g, gUp, gDown)); } char G[101][101], Gr[101][101]; VI dp[2]; int main() { FILL(minBit, -1); FILL(maxBit, -1); REP(mask,0,1<> R >> C; REP(i,0,R) cin >> G[i]; if (C > R) { REP(i,0,R) REP(j,0,C) Gr[j][i] = G[i][j]; swap(C, R); REP(i,0,R) REP(j,0,C) G[i][j] = Gr[i][j]; } VI g, col(C, -1), crossed; enumGroups(0, g, false, col, crossed); sort(groups.begin(), groups.end()); cerr << groupCount << " states" << endl; int t = 0, nt = 0; VI lastStates = VI(1, 0); dp[t] = VI(groups.size(), -1); dp[t][0] = 0; REP(i,0,R) { REP(j,0,C) { nt = t ^ 1; dp[nt] = VI(groups.size(), -1); VI newStates; REP(ki,0,lastStates.size()) { int k = lastStates[ki]; int pre = dp[t][k]; if (pre == -1) continue; int shopState = addShop(k, j), shopAdd = 0; if (G[i][j] == '.') { int hallwayState = addHallway(k, j), hallwayAdd = 0; if (j - 1 >= 0 && G[i][j - 1] == '.') { // S| if (!isHallway(k, j - 1)) hallwayAdd++; // |S if (isHallway(k, j - 1)) shopAdd++; } if (i - 1 >= 0 && G[i - 1][j] == '.') { // S // - if (!isHallway(k, j)) hallwayAdd++; // - // S if (isHallway(k, j)) shopAdd++; } dp[nt][hallwayState] = max(dp[nt][hallwayState], pre + hallwayAdd); newStates.push_back(hallwayState); if (shopState != -1) { dp[nt][shopState] = max(dp[nt][shopState], pre + shopAdd); newStates.push_back(shopState); } } // empty and no shop placement, or connecting to an exit if (G[i][j] != '#') { int hallwayExitState = addHallway(k, j, G[i][j] == 'U' ? 1 : G[i][j] == 'D' ? -1 : 0); dp[nt][hallwayExitState] = max(dp[nt][hallwayExitState], pre); newStates.push_back(hallwayExitState); } // no use and not connected if (shopState != -1) { dp[nt][shopState] = max(dp[nt][shopState], pre); newStates.push_back(shopState); } } sort(newStates.begin(), newStates.end()); newStates.erase(unique(newStates.begin(), newStates.end()), newStates.end()); lastStates = newStates; t ^= 1; } } int ans = 0; REP(ki,0,lastStates.size()) { int k = lastStates[ki]; if (dp[t][k] == -1) continue; if (groups[k].g.empty() || (groups[k].g.size() == 1 && groups[k].gUp == 0 && groups[k].gDown == 0)) ans = max(ans, dp[t][k]); } cout << ans << endl; return 0; }