#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <string>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#include <unordered_set>
#include <unordered_map>
#include <sstream>
#include <complex>
#include <ctime>
#include <cassert>
#include <functional>

using namespace std;

typedef long long ll;
typedef vector<int> VI;
typedef pair<int,int> 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<<MAXN], maxBit[1<<MAXN];
class Group {
public:
  VI g, colg;
  int gUp, gDown, empty;
  Group(VI &_g, int _gUp, int _gDown) {
    g = _g;
    gUp = _gUp; gDown = _gDown;
		int gUpSave = gUp >= 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<Group> 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 handles all other components except for Up and Down, and will thus cause WA
		// we can surely allow specially Up and Down components to be interleaving, but it doesn't seem improve the speed significantly
		// because the number of states are pretty much the same
		// 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) {
			if (gUp == -1) gUp = newUpDown;
			else if (gUp != newUpDown) mergeGroup(g, gUp, gDown, gUp, newUpDown);
		} else if (upDown == -1) {
			if (gDown == -1) gDown = newUpDown;
			else if (gDown != newUpDown) mergeGroup(g, gUp, gDown, 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<<MAXN) {
    REP(b,0,MAXN) {
      if (mask & (1 << b)) {
        if (minBit[mask] == -1) minBit[mask] = b;
        maxBit[mask] = b;
      }
    }
  }
	cin >> 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;
}
