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

#include <algorithm>
#include <iostream>
#include <map>
#include <string>
#include <vector>
using namespace std;

const int MAXN = 50;
const int MAXM = 40;

class UnionFind {
private:
  int n;
  int *par, *rank;

public:
  UnionFind(int _n) {
    n = _n;
    par = new int[n];
    rank = new int[n];
    for (int i = 0; i < n; ++i) {
      par[i] = i;
      rank[i] = 0;
    }
  }

  ~UnionFind() {
    delete[] par;
    delete[] rank;
  }

  int find(int x) {
    if (par[x] == x)
      return x;
    return par[x] = find(par[x]);
  }

  bool same(int x, int y) { return find(x) == find(y); }

  void unite(int x, int y) {
    x = find(x);
    y = find(y);
    if (x == y)
      return;
    if (rank[x] < rank[y]) {
      par[x] = y;
    } else {
      par[y] = x;
      if (rank[x] == rank[y]) {
        ++rank[x];
      }
    }
  }
};

struct Edge {
  int a, b;
};

int N, M;
map<string, int> L;
vector<string> rL;
vector<int> S;
vector<int> V[6];
vector<Edge> E[MAXN];

void rec(int k, int i, int bit) {
  V[k].push_back(bit);
  if (k == 5)
    return;
  for (; i < N; ++i) {
    if (bit & (1 << i))
      continue;
    rec(k + 1, i + 1, bit | (1 << i));
  }
}

bool test(int bit) {
  UnionFind uf(M);
  int cnt = 0;
  for (int i = 0; i < N; ++i) {
    if (bit & (1 << i)) {
      for (int j = 0; j < E[i].size(); ++j) {
        const Edge &e = E[i][j];
        if (!uf.same(e.a, e.b)) {
          uf.unite(e.a, e.b);
          ++cnt;
        }
      }
    }
  }
  return cnt == M - 1;
}

int main() {
  bool first = true;
  while (cin >> N >> M && (N | M)) {
    L.clear();
    rL.clear();
    for (int i = 0; i < N; ++i) {
      string s;
      cin >> s;
      L[s] = L.size() - 1;
      rL.push_back(s);
    }
    S = vector<int>(M, 0);
    for (int j = 0; j < M; ++j) {
      int k;
      cin >> k;
      while (k--) {
        string s;
        cin >> s;
        S[j] |= (1 << L[s]);
      }
    }
    for (int i = 0; i < 6; ++i)
      V[i].clear();
    rec(0, 0, 0);

    for (int i = 0; i < MAXN; ++i)
      E[i].clear();
    for (int a = 0; a < M; ++a) {
      for (int b = a + 1; b < M; ++b) {
        int bit = (S[a] & S[b]);
        for (int k = 0; k < N; ++k) {
          if (bit & (1 << k)) {
            E[k].push_back((Edge){a, b});
          }
        }
      }
    }

    int ans = 0;
    try {
      for (int i = 1; i <= 5; ++i) {
        for (int j = 0; j < V[i].size(); ++j) {
          if (test(V[i][j])) {
            ans = V[i][j];
            throw 0;
          }
        }
      }
    } catch (...) {
    }

    if (first)
      first = false;
    else
      cout << endl;
    if (ans) {
      vector<string> v;
      for (int i = 0; i < N; ++i) {
        if (ans & (1 << i))
          v.push_back(rL[i]);
      }
      cout << v.size() << endl;
      for (int i = 0; i < v.size(); ++i) {
        cout << v[i] << endl;
      }
    } else {
      cout << "Impossible" << endl;
    }
  }
  return 0;
}

Error: MLE

Fixed submission:

#include <algorithm>
#include <iostream>
#include <map>
#include <string>
#include <vector>
using namespace std;

const int MAXN = 50;
const int MAXM = 40;

class UnionFind {
private:
  int n;
  int *par, *rank;

public:
  UnionFind(int _n) {
    n = _n;
    par = new int[n];
    rank = new int[n];
    for (int i = 0; i < n; ++i) {
      par[i] = i;
      rank[i] = 0;
    }
  }

  ~UnionFind() {
    delete[] par;
    delete[] rank;
  }

  int find(int x) {
    if (par[x] == x)
      return x;
    return par[x] = find(par[x]);
  }

  bool same(int x, int y) { return find(x) == find(y); }

  void unite(int x, int y) {
    x = find(x);
    y = find(y);
    if (x == y)
      return;
    if (rank[x] < rank[y]) {
      par[x] = y;
    } else {
      par[y] = x;
      if (rank[x] == rank[y]) {
        ++rank[x];
      }
    }
  }
};

struct Edge {
  int a, b;
};

int N, M;
map<string, int> L;
vector<string> rL;
vector<int> S;
vector<int> V[6];
vector<Edge> E[MAXN];

void rec(int k, int bit) {
  V[k].push_back(bit);
  if (k == 5)
    return;
  for (int i = 0; i < N; ++i) {
    if (bit & (1 << i))
      continue;
    rec(k + 1, bit | (1 << i));
  }
}

bool test(int bit) {
  UnionFind uf(M);
  int cnt = 0;
  for (int i = 0; i < N; ++i) {
    if (bit & (1 << i)) {
      for (int j = 0; j < E[i].size(); ++j) {
        const Edge &e = E[i][j];
        if (!uf.same(e.a, e.b)) {
          uf.unite(e.a, e.b);
          ++cnt;
        }
      }
    }
  }
  return cnt == M - 1;
}

int main() {
  bool first = true;
  while (cin >> N >> M && (N | M)) {
    L.clear();
    rL.clear();
    for (int i = 0; i < N; ++i) {
      string s;
      cin >> s;
      L[s] = L.size() - 1;
      rL.push_back(s);
    }
    S = vector<int>(M, 0);
    for (int j = 0; j < M; ++j) {
      int k;
      cin >> k;
      while (k--) {
        string s;
        cin >> s;
        S[j] |= (1 << L[s]);
      }
    }
    for (int i = 0; i < 6; ++i)
      V[i].clear();
    rec(0, 0);

    for (int i = 0; i < MAXN; ++i)
      E[i].clear();
    for (int a = 0; a < M; ++a) {
      for (int b = a + 1; b < M; ++b) {
        int bit = (S[a] & S[b]);
        for (int k = 0; k < N; ++k) {
          if (bit & (1 << k)) {
            E[k].push_back((Edge){a, b});
          }
        }
      }
    }

    int ans = 0;
    try {
      for (int i = 1; i <= 5; ++i) {
        for (int j = 0; j < V[i].size(); ++j) {
          if (test(V[i][j])) {
            ans = V[i][j];
            throw 0;
          }
        }
      }
    } catch (...) {
    }

    if (first)
      first = false;
    else
      cout << endl;
    if (ans) {
      vector<string> v;
      for (int i = 0; i < N; ++i) {
        if (ans & (1 << i))
          v.push_back(rL[i]);
      }
      cout << v.size() << endl;
      for (int i = 0; i < v.size(); ++i) {
        cout << v[i] << endl;
      }
    } else {
      cout << "Impossible" << endl;
    }
  }
  return 0;
}