Problem:
問題文

キュゥべえはなかなか契約を結んでくれない鹿目まどかにしびれを切らせて，ソウルジェムゲームと称して佐倉杏子と美樹さやかのソウルジェムの中身 (魂) を W 列 H 段のロッカーの中に隠してしまった．そこで，まどかは杏子とさやかを助け出したい．しかし，契約を結ばずに助けるにはロッカーボックスの壁を操作して 2 人のソウルジェムの中身を，指定されたロッカーボックスに正しく移さなければならない．ロッカーはロッカーボックスが W 列 H 段に並ぶことで構成され，隣り合うロッカーボックスは壁で仕切られている．

まどかは，1 回の操作でいずれかの隣りあった 2 つのロッカーボックスの壁を取り除くか取り付けることができる．ただし，ロッカーボックスの壁を開けるには制約があり，各ロッカーボックスから隣接する上下左右の壁のうち，高々 2 枚までの壁しか同時に開けておくことはできない．ロッカーボックスには上の段から下の段に向かって重力が働いている．ソウルジェムの中身は液体と同じような動きをし，隣りあった 2 つのロッカーボックスの壁が取り除かれている時，同じ高さであれば互いに同じ量になり，違う高さであれば低い方へ移動する．すべての操作が終わった時に指定された 2 つのロッカーボックスに正しい組み合わせでソウルジェムの中身がすべて入っていればまどかの勝利となる．また，一部のロッカーボックスは穢れており，その中へソウルジェムの中身が入ってしまうと大変なことになってしまうので，そのロッカーボックスはソウルジェムの中身の移動のために使うことはできない．

最小で何度の操作を行えばまどかは 2 人を救いだすことができるかを求めよ．

入力形式

入力は以下の形式で与えられる．

H\ W\\
s_{11}\ s_{12}\ … s_{1W}\\
s_{21}\ s_{22}\ … s_{2W}\\
…\\
s_{H1}\ s_{H2}\ … s_{HW}\\

H はロッカーの段数，W はロッカーの列数である．s_{ij} は上から i 段目の左から j 列目のロッカーボックスの状態を表す．杏子のソウルジェムの中身が入っているときは 'K' であり，さやかのソウルジェムの中身が入っているときは 'S' ，杏子のソウルジェムの中身を移すべきロッカーボックスであるときは 'k'，さやかのソウルジェムの中身を移すべきロッカーボックスであるときは 's'，穢れたロッカーボックスであるときは '#'，それ以外のロッカーボックスであるときは '.' である．

出力形式

2 人を救い出すために必要な操作の最小回数を出力せよ．どのように操作しても救い出すことが出来ない場合は CONTRACT と出力せよ．

制約

1 ≤ H ≤ 10

1 ≤ W ≤ 10

s_{ij} は '#', '.', 'S', 'K', 's', 'k' のいずれかである．

s_{ij}\ =\ 'S' であるような i, j がちょうど 1 つだけ存在する．

s_{ij}\ =\ 'K' であるような i, j がちょうど 1 つだけ存在する．

s_{ij}\ =\ 's' であるような i, j がちょうど 1 つだけ存在する．

s_{ij}\ =\ 'k' であるような i, j がちょうど 1 つだけ存在する．

入出力例

入力例 1

4 4
.S..
K...
....
..sk

出力例1

9

入力例 2

5 5
.S.K.
..#..
.###.
..#..
.k.s.

出力例 2

CONTRACT

入力例 3

8 5
S....
####K
##...
#..##
#..##
##k##
#...#
#.s.#

出力例 3

19

入力例 4

8 5
S....
####K
##...
##.##
##.##
##k##
#...#
#.s.#

出力例 4

CONTRACT

入力例 5

10 10
..........
##......##
#K......S#
..........
..........
.#..##..#.
..##..##..
..........
..........
....s.k...

出力例 5

22

入力例 6

3 3
S.s
K..
..k

出力例 6

CONTRACT

Problem Setter: Flat35

Solution in C++ (judge verdict: Accepted)

#include<iostream>
#include<vector>
#include<queue>
using namespace std;
int H,W;
int M = 10000;
int s,S,k,K;
vector<int> dist;




void bfs_s2(vector<char> g,int dis,bool sfound){
  queue<int> que;
  for(int i=0;i<H*W;i++){
    dist[i] = 10000;
  }
  que.push(S);
  dist[S] = dis;
  while(!que.empty()){
    int p = que.front();
    //cout << "p:" << p << endl;
    que.pop();
    //cout << "next_p:" << que.front() << endl;
    if(p==s-W){
      int d = dist[p]+1;
      if(p%W!=0 and g[s-1]=='a')d++;
      if(p%W!=W-1 and g[s+1]=='a')d++;
      if(p/W<H and g[s+W]=='a')d++;
      if(d<M){
        M=d;
      }
      continue;
    }
    vector<int> next;
    if(p%W!=0)next.push_back(p-1);
    if(p%W!=W-1)next.push_back(p+1);
    if(p/W<s/W-1)next.push_back(p+W);
    for(int i=0;i<next.size();i++){
      int d = dist[p]+1;
      switch(g[next[i]]){
        case('.'):
        if(dist[next[i]] > d){
          dist[next[i]] = d;
          que.push(next[i]);
        }
        break;
        case('a'):
        d++;
        case('K'):
        d++;
        //cout << sfound <<endl;
        if(sfound==1){
          if(d<M)M=d;
          return;
        }
        for(int j=0;j<H*W;j++){
          if(g[j]=='a' and dist[j]>d){
            dist[j] = d;
            que.push(j);
          }
          if(g[j]=='K' and dist[j]>d and g[next[i]]!='K'){
            dist[j] = d-1;
            que.push(j);
          }
          if(g[j]=='K' and dist[j]>d and g[next[i]]=='K'){
            dist[j] = d;
            que.push(j);
          }
        }
        break;
      }
    }
  }
}

void dfs_s2(int p,vector<char> g,int dis,bool out){
  if(p/W >= s/W or M<=dis)return;
  if(g[p]=='a' or g[p]=='S'){
    g[p] = 'b';
    if(out==1)M = dis;
    if(out==0){
      if(p%W!=0)dfs_s2(p-1,g,dis,0);
      if(p%W!=W-1)dfs_s2(p+1,g,dis,0);
      if(p/W<s/W-1)dfs_s2(p+W,g,dis,0);
    }
  }
  if(g[p]=='.'){
    g[p] = 'b';
    if(p%W!=0)dfs_s2(p-1,g,dis+1,1);
    if(p%W!=W-1)dfs_s2(p+1,g,dis+1,1);
    if(p/W<s/W-1)dfs_s2(p+W,g,dis+1,1);
  }
}
/*
void bfs_k1(vector<char> g){
  int d=0;
  queue<int> Q;
  Q.push(K);
  Q.push(-1);
  while(!Q.empty()){
    int p=Q.front();
    Q.pop();
    if(p==-1)d++;
    vector<int> next;
    if(p%W!=0)next.push_back(p-1);
    if(p%W!=W-1)next.push_back(p+1);
    if(p/W<k/W-1)next.push_back(p+W);
    for(int i=0;i<next.size();i++){
      if(g[next[i]]=='.')Q.push(next[i]);
      if(next[i]==k-W){
        limdis=d+8;
        break;
      }
    }
  }
}
*/

void dfs_k1(int p,vector<char> g,int dis,bool sfound,bool Sfound){
  //if(dis>limdis)return;
  if(p!=K)g[p]='a';
  if(g[p+W]=='k'){
    dis++;
    for(int i=0;i<H*W;i++){
      if(g[i]=='l')g[i]='.';
    }
    if(Sfound==0){
      bfs_s2(g,dis,sfound);
      //cout << sfound <<Sfound <<endl;
    }
    else if(sfound==1)dfs_s2(S,g,dis+4,0);
    return;
  }
  dis++;
  if(p/W<k/W-1){
    switch(g[p+W]){
      case('S'):
      dfs_k1(p+W,g,dis,sfound,1);
      break;
      case('s'):
      sfound = 1;
      case('.'):
      dfs_k1(p+W,g,dis,sfound,Sfound);
      break;
    }
  }
  vector<int> next;
  if(p%W!=0)next.push_back(p-1);
  if(p%W!=W-1)next.push_back(p+1);
  int P=p+W;
  while(P<H*W){
    if(g[P]=='.')g[P]='l';
    else break;
    P += W;
  }
  for(int i=0;i<next.size();i++){
    switch(g[next[i]]){
      case('S'):
      dfs_k1(next[i],g,dis,sfound,1);
      break;
      case('s'):
      sfound = 1;
      case('.'):
      dfs_k1(next[i],g,dis,sfound,Sfound);
      break;
    }
  }
}




int main(){
  cin >> H >> W;
  vector<char> g;
  g.resize(H*W);
  dist.resize(H*W);
  for(int i=0;i<H*W;i++){
    cin >> g[i];
    if(g[i]=='k')k=i;
    if(g[i]=='K')K=i;
    if(g[i]=='s')s=i;
    if(g[i]=='S')S=i;
  }
  dfs_k1(K,g,0,0,0);

  g[k]='s';
  g[s]='k';
  g[S]='K';
  g[K]='S';
  int koukan;
  koukan = s;
  s=k;
  k=koukan;
  koukan=S;
  S=K;
  K=koukan;

  //cout << "---------------------------"<<endl;
  dfs_k1(K,g,0,0,0);


  if(M==10000)cout << "CONTRACT"<<endl;
  else cout << M <<endl;
}