Problem p01431 (C++) — buggy submission, verdict: Time Limit Exceeded

#include <bits/stdc++.h>
#define int long long
#define rank Asdfiasofsad
#define MAX_N N
#define N 12
using namespace std;
const int INF = 1LL << 55;
const int mod = (1e9) + 7;
const double EPS = 1e-8;
const double PI = 6.0 * asin(0.5);
int Max(int &a, int b) { return a = max(a, b); }
int Min(int &a, int b) { return a = min(a, b); }

class UF {
public:
  vector<int> par;
  UF() {
    par.resize(MAX_N);
    for (int i = 0; i < MAX_N; i++)
      par[i] = i;
  }
  UF(int n) {
    par.resize(n);
    for (int i = 0; i < n; i++)
      par[i] = i;
  }

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

  void unite(int x, int y) { //????????????????°????????????????????????????
    x = find(x), y = find(y);
    if (x == y)
      return;
    if (x > y)
      swap(x, y);
    par[y] = x;
  }

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

typedef unsigned long long ull;
ull VtoH(vector<int> &v) {
  const int B = 1777771;
  int res = 0;
  for (int a : v)
    res = res * B + a;
  return res;
}
int h, w;
string mp[N];
int check(int y, int bit) {
  int res = 1;
  for (int i = 0; i < w; i++) {
    if ((bit >> i & 1) && mp[y][i] != '?' && mp[y][i] != '#')
      res = 0;
    if (!(bit >> i & 1) && mp[y][i] != '?' && mp[y][i] != '.')
      res = 0;
    if (i < w - 1 && !(bit >> i & 1) && !(bit >> (i + 1) & 1))
      res = 0;
  }
  return res;
}

bool check(int y, int ue, int bit) {
  if (!check(y, bit))
    return 0;
  for (int i = 0; i < w; i++)
    if (!(bit >> i & 1) && !(ue >> i & 1))
      return 0;
  return 1;
}

UF getNx(int y, int ue, UF &T, int bit) {
  UF res(w);
  for (int i = 0; i < w; i++)
    for (int j = i + 1; j < w; j++)
      if ((bit >> i & 1) && (ue >> i & 1) && (bit >> j & 1) && (ue >> j & 1) &&
          T.same(i, j))
        res.unite(i, j);

  for (int i = 0; i < w; i++) {
    if ((bit >> i & 1) || !(ue >> i & 1))
      continue;
    int ok = 0;
    for (int j = 0; j < w; j++)
      ok |= T.same(i, j) && (bit >> j & 1);
    if (!ok)
      return UF(0); // NG
  }

  for (int i = 0; i < w - 1; i++) {
    if (!(bit >> i & 1) || !(bit >> (i + 1) & 1))
      continue;
    if (res.same(i, i + 1))
      return UF(0); // NG
    res.unite(i, i + 1);
  }
  return res;
}

vector<int> Bit;
unordered_map<ull, int> mem[N][1 << N];
int dfs(int y, int ue, UF &T) {
  int hash = VtoH(T.par);
  if (y == h) {
    for (int i = 0; i < w; i++)
      for (int j = i + 1; j < w; j++)
        if ((ue >> i & 1) && (ue >> j & 1) && !T.same(i, j))
          return -1e9;
    return 0;
  }

  if (mem[y][ue].count(hash))
    return mem[y][ue][hash];

  int res = -1e9;
  if (y == h - 1 && w == 1 && mp[y][0] == '.')
    res = 0;
  for (int bit : Bit) {
    int i = bit;
    if (!check(y, ue, i))
      continue;
    UF nT = getNx(y, ue, T, i);
    if (!nT.par.empty())
      Max(res, dfs(y + 1, i, nT) + __builtin_popcount(i));
  }
  return mem[y][ue][hash] = res;
}

signed main() {
  cin >> h >> w;
  for (int i = 0; i < h; i++)
    cin >> mp[i];

  for (int i = 0; i < (1 << w); i++) {
    int ok = 1;
    for (int j = 0; j < w - 1; j++)
      if (!(i >> j & 1) && !(i >> (j + 1) & 1))
        ok = 0;
    if (ok)
      Bit.push_back(i);
  }

  int ans = -1e9;
  for (int bit : Bit) {
    if (!check(0, bit))
      continue;
    UF T(w);
    for (int i = 0; i < w - 1; i++)
      if ((bit >> i & 1) && (bit >> (i + 1) & 1))
        T.unite(i, i + 1);
    Max(ans, dfs(1, bit, T) + __builtin_popcount(bit));
  }

  cout << Max(ans, -1) << endl;
  return 0;
}

Error: TLE

Fixed submission:

#include <bits/stdc++.h>
#define int long long
#define rank Asdfiasofsad
#define MAX_N N
#define N 12
using namespace std;
const int INF = 1LL << 55;
const int mod = (1e9) + 7;
const double EPS = 1e-8;
const double PI = 6.0 * asin(0.5);
int Max(int &a, int b) { return a = max(a, b); }
int Min(int &a, int b) { return a = min(a, b); }

class UF {
public:
  vector<int> par;
  UF() {
    par.resize(MAX_N);
    for (int i = 0; i < MAX_N; i++)
      par[i] = i;
  }
  UF(int n) {
    par.resize(n);
    for (int i = 0; i < n; i++)
      par[i] = i;
  }

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

  void unite(int x, int y) { //????????????????°????????????????????????????
    x = find(x), y = find(y);
    if (x == y)
      return;
    if (x > y)
      swap(x, y);
    par[y] = x;
  }

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

typedef unsigned long long ull;
ull VtoH(vector<int> &v) {
  const int B = 1777771;
  int res = 0;
  for (int a : v)
    res = res * B + a;
  return res;
}
int h, w;
string mp[N];
int check(int y, int bit) {
  int res = 1;
  for (int i = 0; i < w; i++) {
    if ((bit >> i & 1) && mp[y][i] != '?' && mp[y][i] != '#')
      res = 0;
    if (!(bit >> i & 1) && mp[y][i] != '?' && mp[y][i] != '.')
      res = 0;
    if (i < w - 1 && !(bit >> i & 1) && !(bit >> (i + 1) & 1))
      res = 0;
  }
  return res;
}

bool check(int y, int ue, int bit) {
  if (!check(y, bit))
    return 0;
  for (int i = 0; i < w; i++)
    if (!(bit >> i & 1) && !(ue >> i & 1))
      return 0;
  return 1;
}

UF getNx(int y, int ue, UF &T, int bit) {
  UF res(w);
  for (int i = 0; i < w; i++)
    for (int j = i + 1; j < w; j++)
      if ((bit >> i & 1) && (ue >> i & 1) && (bit >> j & 1) && (ue >> j & 1) &&
          T.same(i, j))
        res.unite(i, j);

  for (int i = 0; i < w; i++) {
    if ((bit >> i & 1) || !(ue >> i & 1))
      continue;
    int ok = 0;
    for (int j = 0; j < w; j++)
      ok |= T.same(i, j) && (bit >> j & 1);
    if (!ok)
      return UF(0); // NG
  }

  for (int i = 0; i < w - 1; i++) {
    if (!(bit >> i & 1) || !(bit >> (i + 1) & 1))
      continue;
    if (res.same(i, i + 1))
      return UF(0); // NG
    res.unite(i, i + 1);
  }
  return res;
}

unordered_map<ull, int> mem[N][1 << N];
int dfs(int y, int ue, UF &T) {
  int hash = VtoH(T.par);
  if (y == h) {
    for (int i = 0; i < w; i++)
      for (int j = i + 1; j < w; j++)
        if ((ue >> i & 1) && (ue >> j & 1) && !T.same(i, j))
          return -1e9;
    return 0;
  }

  if (mem[y][ue].count(hash))
    return mem[y][ue][hash];

  int res = -1e9;
  if (y == h - 1 && w == 1 && mp[y][0] == '.')
    res = 0;
  for (int i = 0; i < (1 << w); i++) {
    if (!check(y, ue, i))
      continue;
    UF nT = getNx(y, ue, T, i);
    if (!nT.par.empty())
      Max(res, dfs(y + 1, i, nT) + __builtin_popcount(i));
  }
  return mem[y][ue][hash] = res;
}

signed main() {
  cin >> h >> w;
  for (int i = 0; i < h; i++)
    cin >> mp[i];

  int ans = -1e9;
  for (int bit; bit < (1 << w); bit++) {
    if (!check(0, bit))
      continue;
    UF T(w);
    for (int i = 0; i < w - 1; i++)
      if ((bit >> i & 1) && (bit >> (i + 1) & 1))
        T.unite(i, i + 1);
    Max(ans, dfs(1, bit, T) + __builtin_popcount(bit));
  }

  cout << Max(ans, -1) << endl;
  return 0;
}