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

#include <algorithm>
#include <cstdio>
#include <cstring>
#include <functional>
#include <vector>

#define rep(i, n) for (int i = 0; i < (n); i++)

using namespace std;

struct square {
  int x, y, a; // 左上の座標, 幅
  bool operator<(const square &S) const { return a < S.a; }
};

int h, w;
int B[10][10];

vector<square> S;
int cnt[10][10]; // マス (i, j) を覆うことのできる正方形の個数

#define update_cnt(i, d)                                                       \\
  for (int y = S[i].y; y < S[i].y + S[i].a; y++)                               \\
    for (int x = S[i].x; x < S[i].x + S[i].a; x++)                             \\
  cnt[y][x] += d

int hstar(int i) {
  int n = 0;
  static int val
      [100]; // i 番目以降の正方形で新たに覆えるマスの個数を大きい順に並べたもの
  for (; i < S.size(); i++) {
    val[n] = 0;
    for (int y = S[i].y; y < S[i].y + S[i].a; y++)
      for (int x = S[i].x; x < S[i].x + S[i].a; x++) {
        if (B[y][x] == 1)
          val[n]++;
      }
    n++;
  }
  sort(val, val + n, greater<int>());

  int a = 0; // まだ覆っていないマスの数
  rep(y, h) rep(x, w) if (B[y][x] == 1) a++;

  int res = 0;
  for (i = 0; a > 0; i++) {
    a -= val[i];
    res++;
  }
  return res;
}

int res;
void dfs(int i, int sum, int ub) {
  if (sum + hstar(i) == ub)
    return;
  if (sum + hstar(i) >= res)
    return;

  if (i == S.size()) {
    res = sum;
    return;
  }

  bool ok1 = false, ok2 = false;
  for (int y = S[i].y; y < S[i].y + S[i].a; y++)
    for (int x = S[i].x; x < S[i].x + S[i].a; x++) {
      if (B[y][x] == 1)
        ok1 = true;
      if (B[y][x] == 1 && cnt[y][x] == 1)
        ok2 = true;
    }

  bool use = true, notuse = true;
  // 正方形 i を使うことで新たに覆えるマスがないなら使わない
  if (!ok1)
    use = false;
  // 正方形 i を使わないと絶対に覆えないマスができるようなら使う
  if (ok2)
    notuse = false;

  // いずれでもなければ両方試す
  update_cnt(i, -1);
  if (use) {
    int tmp[10][10];
    memcpy(tmp, B, sizeof B);
    for (int y = S[i].y; y < S[i].y + S[i].a; y++)
      for (int x = S[i].x; x < S[i].x + S[i].a; x++)
        B[y][x] = i + 2;
    dfs(i + 1, sum + 1, ub);
    memcpy(B, tmp, sizeof B);
  }
  if (notuse) {
    dfs(i + 1, sum, ub);
  }
  update_cnt(i, +1);
}

int main() {
  for (; scanf("%d%d", &w, &h), w;) {
    rep(i, h) rep(j, w) scanf("%d", B[i] + j);

    S.clear();
    rep(i, h) rep(j, w) if (B[i][j] == 1) {
      int a;
      for (a = 1; i + a <= h && j + a <= w; a++) {
        bool ok = true;
        for (int y = i; y < i + a; y++)
          for (int x = j; x < j + a; x++)
            if (B[y][x] == 0)
              ok = false;
        if (!ok)
          break;
      }
      S.push_back((square){j, i, a - 1});
    }

    // 他の正方形に完全に覆われるような正方形を削除
    rep(i, S.size()) {
      bool covered = false;
      rep(j, S.size()) if (i != j) {
        if (S[j].x <= S[i].x && S[j].y <= S[i].y &&
            S[i].x + S[i].a <= S[j].x + S[j].a &&
            S[i].y + S[i].a <= S[j].y + S[j].a)
          covered = true;
      }
      if (covered) {
        S.erase(S.begin() + i);
        i--;
      }
    }
    sort(S.begin(), S.end()); // 小さい正方形から順に調べる

    rep(i, h) rep(j, w) cnt[i][j] = 0;
    rep(i, S.size()) update_cnt(i, 1);

    res = S.size() + 1;
    for (int ub = 1;; ub++) {
      dfs(0, 0, ub);
      if (res < S.size() + 1)
        break;
    }
    printf("%d\\n", res);
  }

  return 0;
}

Error: TLE

Fixed submission:

#include <algorithm>
#include <cstdio>
#include <cstring>
#include <vector>

#define rep(i, n) for (int i = 0; i < (n); i++)

using namespace std;

struct square {
  int x, y, a; // 左上の座標, 幅
  bool operator<(const square &S) const { return a < S.a; }
};

int h, w;
int B[10][10];

vector<square> S;
int cnt[10][10]; // マス (i, j) を覆うことのできる正方形の個数

#define update_cnt(i, d)                                                       \\
  for (int y = S[i].y; y < S[i].y + S[i].a; y++)                               \\
    for (int x = S[i].x; x < S[i].x + S[i].a; x++)                             \\
  cnt[y][x] += d

int res;
void dfs(int i, int sum, int ub) {
  if (sum == ub)
    return;
  if (sum >= res)
    return;

  if (i == S.size()) {
    res = sum;
    return;
  }

  bool ok1 = false, ok2 = false;
  for (int y = S[i].y; y < S[i].y + S[i].a; y++)
    for (int x = S[i].x; x < S[i].x + S[i].a; x++) {
      if (B[y][x] == 1)
        ok1 = true;
      if (B[y][x] == 1 && cnt[y][x] == 1)
        ok2 = true;
    }

  bool use = true, notuse = true;
  // 正方形 i を使うことで新たに覆えるマスがないなら使わない
  if (!ok1)
    use = false;
  // 正方形 i を使わないと絶対に覆えないマスができるようなら使う
  if (ok2)
    notuse = false;

  // いずれでもなければ両方試す
  update_cnt(i, -1);
  if (use) {
    int tmp[10][10];
    memcpy(tmp, B, sizeof B);
    for (int y = S[i].y; y < S[i].y + S[i].a; y++)
      for (int x = S[i].x; x < S[i].x + S[i].a; x++)
        B[y][x] = i + 2;
    dfs(i + 1, sum + 1, ub);
    memcpy(B, tmp, sizeof B);
  }
  if (notuse) {
    dfs(i + 1, sum, ub);
  }
  update_cnt(i, +1);
}

int main() {
  for (; scanf("%d%d", &w, &h), w;) {
    rep(i, h) rep(j, w) scanf("%d", B[i] + j);

    S.clear();
    rep(i, h) rep(j, w) if (B[i][j] == 1) {
      int a;
      for (a = 1; i + a <= h && j + a <= w; a++) {
        bool ok = true;
        for (int y = i; y < i + a; y++)
          for (int x = j; x < j + a; x++)
            if (B[y][x] == 0)
              ok = false;
        if (!ok)
          break;
      }
      S.push_back((square){j, i, a - 1});
    }

    // 他の正方形に完全に覆われるような正方形を削除
    rep(i, S.size()) {
      bool covered = false;
      rep(j, S.size()) if (i != j) {
        if (S[j].x <= S[i].x && S[j].y <= S[i].y &&
            S[i].x + S[i].a <= S[j].x + S[j].a &&
            S[i].y + S[i].a <= S[j].y + S[j].a)
          covered = true;
      }
      if (covered) {
        S.erase(S.begin() + i);
        i--;
      }
    }
    sort(S.begin(), S.end()); // 小さい正方形から順に調べる

    rep(i, h) rep(j, w) cnt[i][j] = 0;
    rep(i, S.size()) {
      for (int y = S[i].y; y < S[i].y + S[i].a; y++)
        for (int x = S[i].x; x < S[i].x + S[i].a; x++) {
          cnt[y][x]++;
        }
    }

    res = S.size() + 1;
    for (int ub = 1;; ub++) {
      dfs(0, 0, ub);
      if (res < S.size() + 1)
        break;
    }
    printf("%d\\n", res);
  }

  return 0;
}