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

#include <cmath>
#include <iostream>
#include <map>
#include <queue>
#include <vector>

using namespace std;

void part(int x, vector<int> &d, vector<vector<int>> &a, int pre) {
  if (x == 0) {
    a.push_back(d);
  }

  for (int i = pre; i >= 1; --i) {
    if (x - i >= 0) {
      d.push_back(i);
      part(x - i, d, a, i);
      d.pop_back();
    }
  }
}

const int NPAT = 41;
int res;
int parts[NPAT][9];

inline int ideal(const vector<int> &m) {
  return (m[0] + 2 * m[1] + 3 * m[2] + 4 * m[3] + 5 * m[4] + 6 * m[5] +
          7 * m[6] + 8 * m[7] + 9 * m[8]) /
         10;
}

bool solve(vector<int> &m, int pre, int step) {
  if (res < step) {
    res = step;
  }

  if (step + ideal(m) <= res) {
    return false;
  }

  for (int i = pre; i < NPAT; ++i) {
    bool packable = true;

    for (int j = 0; j < 9; ++j) {
      if (m[j] < parts[i][j]) {
        packable = false;
      }
    }

    if (packable) {
      // Translate
      for (int j = 0; j < 9; ++j) {
        m[j] -= parts[i][j];
      }

      solve(m, i, step + 1);

      // Rollback
      for (int j = 0; j < 9; ++j) {
        m[j] += parts[i][j];
      }
    }
  }
  return false;
}

int main(void) {
  vector<int> d;
  vector<vector<int>> s;
  part(10, d, s, 9);

  for (int sz = 2; sz < 22; ++sz) {
    for (int i = 0; i < (int)s.size(); ++i) {
      if (s[i].size() == sz) {
        for (int j = 0; j < (int)s[i].size(); ++j) {
          parts[i][s[i][j] - 1]++;
        }
      }
    }
  }

  while (true) {
    int n;
    vector<int> m(9, 0);
    cin >> n;

    if (n == 0) {
      break;
    }

    for (int i = 0; i < n; ++i) {
      int tmp;
      cin >> tmp;
      m[tmp - 1]++;
    }

    res = 0;

    for (int i = 0; i < 4; ++i) {
      int t = min(m[8 - i], m[i]);
      m[8 - i] -= t;
      m[i] -= t;
      res += t;
    }
    if (m[4] >= 2) {
      res += m[4] / 2;
      m[4] %= 2;
    }

    solve(m, 0, res);
    cout << res << endl;
  }
  return 0;
}

Error: TLE

Fixed submission:

#include <cmath>
#include <iostream>
#include <vector>

using namespace std;

void part(int x, vector<int> &d, vector<vector<int>> &a, int pre) {
  if (x == 0) {
    a.push_back(d);
  }

  for (int i = pre; i >= 1; --i) {
    if (x - i >= 0) {
      d.push_back(i);
      part(x - i, d, a, i);
      d.pop_back();
    }
  }
}

const int NPAT = 41;
int res;
int greedy;
int parts[NPAT][9];

inline int ideal(int m[]) {
  return (m[0] + 2 * m[1] + 3 * m[2] + 4 * m[3] + 5 * m[4] + 6 * m[5] +
          7 * m[6] + 8 * m[7] + 9 * m[8]) /
         10;
}

bool solve(int m[], int pre, int step, bool bgreedy) {
  if (res < step) {
    res = step;
  }

  if (step + ideal(m) <= res) {
    return false;
  }

  if (!bgreedy) {
    if (step + ideal(m) <= greedy) {
      return false;
    }
  }

  for (int i = pre; i < NPAT; ++i) {
    bool packable = true;
    bool ret = false;

    for (int j = 0; j < 9; ++j) {
      if (m[j] < parts[i][j]) {
        packable = false;
      }
    }

    if (packable) {
      // Translate
      for (int j = 0; j < 9; ++j) {
        m[j] -= parts[i][j];
      }

      if (bgreedy) {
        if (solve(m, i, step + 1, bgreedy)) {
          ret = true;
        }
      } else {
        solve(m, i, step + 1, bgreedy);
      }

      // Rollback
      for (int j = 0; j < 9; ++j) {
        m[j] += parts[i][j];
      }

      if (ret)
        return true;
    }
  }
  return true;
}

int main(void) {
  vector<int> d;
  vector<vector<int>> s;
  part(10, d, s, 9);

  for (int sz = 2; sz < 22; ++sz) {
    for (int i = 0; i < (int)s.size(); ++i) {
      if (s[i].size() == sz) {
        for (int j = 0; j < (int)s[i].size(); ++j) {
          parts[i][s[i][j] - 1]++;
        }
      }
    }
  }

  while (true) {
    int n;
    int m[9] = {
        0,
    };

    cin >> n;

    if (n == 0) {
      break;
    }

    for (int i = 0; i < n; ++i) {
      int tmp;
      cin >> tmp;
      m[tmp - 1]++;
    }

    res = greedy = 0;
    solve(m, 0, 0, true);
    greedy = res;
    res = 0;
    solve(m, 0, 0, false);

    if (res < greedy) {
      res = greedy;
    }
    cout << res << endl;
  }
  return 0;
}