#include <bits/stdc++.h>
using namespace std;
#define rep(i,n) for (int i = 0; i < (n); ++i)

//方向を決定する演算子的なもの
int di[] = {-1, 0, 1, 0}; //
int dj[] = {0, -1, 0, 1}; //

int main() {
  int H, W, X, Y;
  cin >> H >> W >> X >> Y;
  --X; //配列変数の関係上デクリメント
  --Y; //同様
  //H行W列のマスの入力
  vector <string> s(H);
  rep(i, H) cin >> s[i];
  int ans = 1; //自身がいるマスを考慮,初期値1
  rep(k, 4) {
    //k=0上方向,k=1左方向,k=2下方向,k=3右方向
  	int ni = X; int nj = Y;
    //マスから出るか、「#」にぶつかるまでkで与えた方向へ動かす
    while(true) {
    	ni += di[k];
      	nj += dj[k];
      	if(ni < 0 || nj < 0 || ni >= H || nj >= W) break;
      	if(s[ni][nj] == '#') break;
      	++ans;
    }
  }
  cout << ans << endl;
}

#include <bits/stdc++.h>
//#include <atcoder/all>
using namespace std;
//using namespace atcoder;
using ll=long long;
using ld=long double;
using pll=pair<ll, ll>;
//using mint = modint1000000007;
#define rep(i,n) for (ll i=0; i<n; ++i)
#define all(c) begin(c),end(c)
#define PI acos(-1)
#define oo 2e18
template<typename T1, typename T2>
bool chmax(T1 &a,T2 b){if(a<b){a=b;return true;}else return false;}
template<typename T1, typename T2>
bool chmin(T1 &a,T2 b){if(a>b){a=b;return true;}else return false;}
//priority_queue<ll, vector<ll>, greater<ll>> Q;
/*

*/
//UnionFind
vector<vector<ll>> G;
vector<bool> seen;
struct UnionFind{
  vector<ll> par,siz;
  
  UnionFind(ll N):par(N+1), siz(N+1, 1){
    for(int i = 0; i <= N; i++)
      par[i] = i;
  }
  
  void mkpar(ll n, ll set){//親はset=根
    for(auto next_n: G[n]){
      if(seen[next_n]) continue;
      seen[next_n] = true;
      par[next_n] = set;
      mkpar(next_n, set);
      siz[n] += siz[next_n];
    }
  }
  
  void mkpar2(ll n){//親は1個上。sizとれる。
    for (auto next_n: G[n]){
      if (seen[next_n]) continue;
      seen[next_n] = true;
      par[next_n] = n;
      mkpar2(next_n);
      siz[n] += siz[next_n];
    }
  }
  
  ll root(ll x){
    if(par[x] == x)
      return x;
    return par[x] = root(par[x]);
  }
  
  void unite(ll x, ll y){
    ll rx = root(x), ry = root(y);
    if(rx == ry)
      return;
    par[ry] = rx;
    siz[rx] += siz[ry];    
  }
  
  bool issame(ll x, ll y){
    return root(x) == root(y);
  }
  
  ll size(ll x){
    return siz[root(x)];
  }
};

ll N, M;
ll X[30];

ll ans=1;
ll tmp=0;
ll tsize=0;
ll cnt=0;

bool check(ll n){
  for(auto v: G[n]){
    if(X[n]==X[v]) return true;
  }
  return false;
}

void dfs2(ll n){
  for(ll i=1; i<=3; i++){
    //まず、隣り合ってないか確認
    X[n]=i;
    if(check(n)) continue;
    if(cnt==tsize)
      tmp++;
    else{
      for(auto v:G[n]){
        if(X[v]) continue;
        dfs2(v);
      }
    }
  }
  X[n]=0;
}

vector<ll> L;
void dfs(ll n){
  if(n==tsize){
    tmp++;
    return ;
  }
  ll v=L[n];
  if(n==0){
    X[v]=1;
    dfs(n+1);
  }
  else{
    for(ll j=1; j<=3; j++){
      X[v]=j;
      if(check(v)) continue;
      dfs(n+1);
    }
    X[v]=0;
  }
}


int main(){
  cin >> N >> M;
  G.assign(N+1, vector<ll>());
  seen.assign(N+1, false);
  rep(i, M){
    ll a, b;
    cin >> a >> b;
    G[a].push_back(b);
    G[b].push_back(a);
  }
  UnionFind tree(N);
  for(ll i = 1; i <= N; i++){
    seen[i] = true;
    tree.mkpar(i, i);
  }
  for(int i = 1; i <= N; i++){
    if(tree.par[i]==i){
      tmp=0;
      L.assign(0, 0);
      for(int j = 1; j <= N; j++)
        if(tree.par[j]==i) L.push_back(j);
      tsize=L.size();
      if(tsize==1) ans*=3;
      else{
        dfs(0);
        ans *= tmp*3;
      }
    }
  }
  cout << ans << endl;
}