Problem p00899 (C++) — buggy submission, verdict: Memory Limit Exceeded

#include <algorithm>
#include <cassert>
#include <cctype>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <fstream>
#include <iomanip>
#include <iostream>
#include <map>
#include <memory.h>
#include <numeric>
#include <queue>
#include <set>
#include <sstream>
#include <string>
#include <vector>
using namespace std;

#define REP2(i, m, n) for (int i = (int)(m); i < (int)(n); i++)
#define REP(i, n) REP2(i, 0, n)
#define ALL(c) (c).begin(), (c).end()
#define ITER(c) __typeof((c).begin())
#define PB(e) push_back(e)
#define FOREACH(i, c) for (ITER(c) i = (c).begin(); i != (c).end(); ++i)
#define MP(a, b) make_pair(a, b)
#define PARITY(n) ((n)&1)

typedef long long ll;
typedef pair<ll, ll> P;
const int INF = 1000 * 1000 * 1000 + 7;
const double EPS = 1e-10;

const int maxn = 14;
const int maxl = 21;

int dp[1 << maxn][maxn][maxl];
int next_str[maxn][maxl][maxn];
int next_len[maxn][maxl][maxn];
int cost[maxn][maxl][maxn];

string needed_str(const string &s1, const string &s2) {
  for (int i = min(s1.size(), s2.size()); i > 0; i--) {
    if (s1.substr(s1.size() - i, i) == s2.substr(0, i))
      return s2.substr(i);
  }
  return s2;
}

void set_next(int &strID, int &len, const string &str,
              const vector<string> &vs) {
  int best = 0;
  REP(i, vs.size()) {
    for (int j = min(str.size(), vs[i].size()); j > 0; j--) {
      if (str.substr(str.size() - j, j) == vs[i].substr(0, j) && best < j) {
        strID = i;
        len = best = j;
      }
    }
  }
}

void init_table(const vector<string> &vs) {
  REP(i, vs.size()) REP(j, vs[i].size() + 1) {
    string s1 = vs[i].substr(0, j);
    REP(k, vs.size()) {
      string s2 = needed_str(s1, vs[k]);
      cost[i][j][k] = s2.size();
      set_next(next_str[i][j][k], next_len[i][j][k], s1 + s2, vs);
    }
  }
}

vector<string> erase_substr(vector<string> vs) {
  int n = vs.size();
  REP(i, n) REP(j, n) if (i != j) {
    if (vs[i] == vs[j]) {
      if (i < j)
        vs[j] = "";
    } else if (vs[i].find(vs[j]) != string::npos) {
      vs[j] = "";
    }
  }
  vector<string> res;
  REP(i, n) if (vs[i] != "") res.PB(vs[i]);
  return res;
}

int main() {
  int N;

  while (cin >> N && N) {
    vector<string> vs;
    REP(i, N) {
      string s;
      cin >> s;
      vs.PB(s);
    }

    vs = erase_substr(vs);
    init_table(vs);

    N = vs.size();
    fill(&dp[0][0][0], &dp[0][0][0] + (1 << maxn) * maxn * maxl, INF);
    dp[0][0][0] = 0;

    REP(mask, 1 << N) REP(i, N) REP(j, vs[i].size() + 1) {
      if (dp[mask][i][j] == INF)
        continue;
      REP(k, N) {
        int nstr = dp[mask][i][j] + cost[i][j][k];
        int &str = dp[mask | (1 << k)][next_str[i][j][k]][next_len[i][j][k]];
        if (str > nstr)
          str = nstr;
      }
    }

    int res = INF;
    REP(i, N) REP(j, vs[i].size() + 1) {
      int s = dp[(1 << N) - 1][i][j];
      if (s != -1)
        res = min(res, s);
    }
    cout << res << endl;
  }
  return 0;
}

Error: MLE

Fixed submission:

#include <algorithm>
#include <cassert>
#include <cctype>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <fstream>
#include <iomanip>
#include <iostream>
#include <map>
#include <memory.h>
#include <numeric>
#include <queue>
#include <set>
#include <sstream>
#include <string>
#include <vector>
using namespace std;

#define REP2(i, m, n) for (int i = (int)(m); i < (int)(n); i++)
#define REP(i, n) REP2(i, 0, n)
#define ALL(c) (c).begin(), (c).end()
#define ITER(c) __typeof((c).begin())
#define PB(e) push_back(e)
#define FOREACH(i, c) for (ITER(c) i = (c).begin(); i != (c).end(); ++i)
#define MP(a, b) make_pair(a, b)
#define PARITY(n) ((n)&1)

typedef long long ll;
typedef pair<ll, ll> P;
const int INF = 1000 * 1000 * 1000 + 7;
const double EPS = 1e-10;

const int maxn = 14;
const int maxl = 21;

string dp[1 << maxn][maxn][maxl];
int next_str[maxn][maxl][maxn];
int next_len[maxn][maxl][maxn];
string cost[maxn][maxl][maxn];

string needed_str(const string &s1, const string &s2) {
  for (int i = min(s1.size(), s2.size()); i > 0; i--) {
    if (s1.substr(s1.size() - i, i) == s2.substr(0, i))
      return s2.substr(i);
  }
  return s2;
}

void set_next(int &strID, int &len, const string &str,
              const vector<string> &vs) {
  int best = 0;
  REP(i, vs.size()) {
    for (int j = min(str.size(), vs[i].size()); j > 0; j--) {
      if (str.substr(str.size() - j, j) == vs[i].substr(0, j) && best < j) {
        strID = i;
        len = best = j;
      }
    }
  }
}

void init_table(const vector<string> &vs) {
  REP(i, vs.size()) REP(j, vs[i].size() + 1) {
    string s1 = vs[i].substr(0, j);
    REP(k, vs.size()) {
      string s2 = needed_str(s1, vs[k]);
      cost[i][j][k] = s2;
      set_next(next_str[i][j][k], next_len[i][j][k], s1 + s2, vs);
    }
  }
}

vector<string> erase_substr(vector<string> vs) {
  int n = vs.size();
  REP(i, n) REP(j, n) {
    if (i == j)
      continue;
    if (vs[i] == vs[j]) {
      if (i < j)
        vs[j] = "";
    } else if (vs[i].find(vs[j]) != string::npos) {
      vs[j] = "";
    }
  }
  vector<string> res;
  REP(i, n) if (vs[i] != "") res.PB(vs[i]);
  return res;
}

int main() {
  int N;

  while (cin >> N && N) {
    vector<string> vs;
    REP(i, N) {
      string s;
      cin >> s;
      vs.PB(s);
    }

    vs = erase_substr(vs);
    init_table(vs);

    fill(&dp[0][0][0], &dp[0][0][0] + (1 << maxn) * maxl * maxn, "");

    N = vs.size();
    REP(mask, 1 << N) REP(i, N) REP(j, vs[i].size() + 1) {
      if ((mask > 0 && dp[mask][i][j] == "") || (mask == 0 && j > 0))
        continue;
      REP(k, N) {
        string new_str = dp[mask][i][j] + cost[i][j][k];
        string &str = dp[mask | (1 << k)][next_str[i][j][k]][next_len[i][j][k]];
        if (str == "" || str.size() > new_str.size() ||
            (str.size() == new_str.size() && str > new_str)) {
          str = new_str;
        }
      }
    }

    string res;
    REP(i, N) REP(j, vs[i].size() + 1) {
      string s = dp[(1 << N) - 1][i][j];
      if (s == "")
        continue;
      if (res == "" || s.size() < res.size()) {
        res = s;
      } else if (s.size() == res.size()) {
        res = min(res, s);
      }
    }
    cout << res.size() << endl;
  }
  return 0;
}