#include <iostream>
#include <sstream>
#include <vector>
#include <string>
#include <map>
#include <set>
#include <algorithm>
#include <stack>
#include <queue>
#include <deque>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <cassert>
#define REP(i,n) for(int i=0; i<(int)(n); ++i)

using namespace std;
typedef long long ll;

const int    INF = 1000000000;
const int    MOD = 1000000007;
const double EPS = 1e-8;

int main(){
    int H, W;
    while(cin >> H >> W){
        vector<string> str(H);
        REP(i, H) cin >> str[i];

        const int MAXS = 1 << W;
        int dp[2][MAXS];
        int* curr = dp[0], *next = dp[1];
        for(int s = 0; s < MAXS; s++) curr[s] = -1;
        curr[0] = 0;
        for(int y = 0; y < H; y++){
            for(int x = 0; x < W; x++){
                for(int s = 0; s < MAXS; s++) next[s] = -1;
                for(int s = 0; s < MAXS; s++) if(curr[s] >= 0){
                    int cu = __builtin_popcount(s >> x); // count of upper
                    int cl = __builtin_popcount(s & ((1 << x) - 1)); // count of lower
                    assert(cu + cl == __builtin_popcount(s));

                    if(cl + (W - 1 - x) >= str[y].size())
                        next[s & ~(1 << x)] = max(next[s & ~(1 << x)], curr[s]); // path through

                    if(cl == str[y].size()) continue;

                    int add = 0;
                    if(cl > 0 && str[y][cl] == str[y][cl - 1] && (s >> (x - 1) & 1)){
                        add += 2;
                    }
                    if(y > 0 && (s >> x & 1) && str[y - 1][str[y - 1].size() - cu] == str[y][cl]){
                        add += 2;
                    }
                    next[s | (1 << x)] = max(next[s | (1 << x)], curr[s] + add);
                }
                swap(curr, next);
            }
        }
        int ans = 0;
        for(int s = 0; s < MAXS; s++) ans = max(ans, curr[s]);
        cout << ans << endl;
    }
    return 0;
}