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

#include <algorithm> // require sort next_permutation count __gcd reverse etc.
#include <cctype>    // require tolower, toupper
#include <cfloat>
#include <climits>
#include <cmath>   // require fabs
#include <cstdio>  // require scanf printf
#include <cstdlib> // require abs exit atof atoi
#include <cstring> // require memset
#include <ctime>   // require srand
#include <deque>
#include <fstream> // require freopen
#include <functional>
#include <iomanip> // require setw
#include <iostream>
#include <limits>
#include <map>
#include <numeric> // require accumulate
#include <queue>
#include <set>
#include <sstream> // require stringstream
#include <stack>
#include <string>
#include <vector>
#define rep(i, n) for (int i = 0; i < (n); i++)
#define ALL(A) A.begin(), A.end()

using namespace std;

typedef long long ll;
typedef pair<int, int> P;
const int MAX_D = 32;
const int MAX_W = 51;
const int MAX_X = 6;

/*
        yuta1024 さんのコード

*/
int C, D, W, X; // C: 地域数 (1 ≦ C ≦ 15 ) D: ツアー数（1 ≦ D ≦ 30 )
                // W:負担の合計の最大値 (0 ≦ W ≦ 50 )
                // X:ツアー期間中ライブを同じ日に2度以上行える合計日数の上限 ( 0
                // ≦ X ≦ 5 )
int E[40][40]; // E[i][j] 地域 i で j 日目にライブを行うことで期待される利益 ( 0
               // ≦ E[i][j] ≦ 1000)
int F[40][40]; // F[i][j] 地域 i で j 日目にライブを行うことで掛かる負担 ( 0 ≦
               // F[i][j] ≦ 10 )

int dp[MAX_D][MAX_W][MAX_X];

int solve(int d, int w, int x) {
  if (d >= D)
    return 0;
  if (dp[d][w][x] != -1)
    return dp[d][w][x];

  int res = solve(d + 1, w, x);
  rep(i, C) {
    if (E[i][d] != 0 && w + F[i][d] <= W) {
      res = max(res, solve(d + 1, w + F[i][d], x) + E[i][d]);
      if (x + 1 <= X) {
        int curr_w = w + F[i][d], curr_e = E[i][d];
        for (int j = i - 1; j >= 0; j--) {
          if (E[j][d] == 0 || curr_w + F[j][d] > W)
            break;
          curr_w += F[j][d];
          curr_e += E[j][d];
          res = max(res, solve(d + 1, curr_w, x + 1) + curr_e);
        } // end for

        curr_w = w + F[i][d], curr_e = E[i][d];
        for (int j = i + 1; j < C; j++) {
          if (E[j][d] == 0 || curr_w + F[j][d] > W)
            break;
          curr_w += F[j][d];
          curr_e += E[j][d];
          res = max(res, solve(d + 1, curr_w, x + 1) + curr_e);
        } // end for
      }   // end if
    }     // end if
  }       // end rep

  return dp[d][w][x] = res;
}

int main() {
  ios_base::sync_with_stdio(0);
  while (cin >> C >> D >> W >> X, C) {
    memset(E, 0, sizeof(E));
    memset(F, 0, sizeof(F));
    rep(i, C) rep(j, D) cin >> E[i][j];
    rep(i, C) rep(j, D) cin >> F[i][j];

    memset(dp, -1, sizeof(dp));
    int res = solve(0, 0, 0);
    cout << res << endl;
  } // end while

  return 0;
}

Error: TLE

Fixed submission:

#include <algorithm> // require sort next_permutation count __gcd reverse etc.
#include <cctype>    // require tolower, toupper
#include <cfloat>
#include <climits>
#include <cmath>   // require fabs
#include <cstdio>  // require scanf printf
#include <cstdlib> // require abs exit atof atoi
#include <cstring> // require memset
#include <ctime>   // require srand
#include <deque>
#include <fstream> // require freopen
#include <functional>
#include <iomanip> // require setw
#include <iostream>
#include <limits>
#include <map>
#include <numeric> // require accumulate
#include <queue>
#include <set>
#include <sstream> // require stringstream
#include <stack>
#include <string>
#include <vector>
#define rep(i, n) for (int i = 0; i < (n); i++)
#define ALL(A) A.begin(), A.end()

using namespace std;

typedef long long ll;
typedef pair<int, int> P;

/*
        Live Schedule AOJ:1086
        元々は
        Ritsumeikan University Programming Camp 2012 , Day 1, Shiga, Japan,
   2012-03-13 C: Live Schedule 現在の問題の提出URL は
        http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=1086

        解法：
        方針としては探索だが
        C-4.cpp までは
        探索木が範囲が広すぎて TLE。
        もう少し探索の範囲を狭くすること。

        C5-0.cpp は C-4.cppの改良。
        しかしこれでもおそらく TLE.


        また DFS の変数を取り方とコードの書き換えになれる事。
        特に再帰の変数の取り方に注意！
*/

int C, D, W, X; // C: 地域数 (1 ≦ C ≦ 15 ) D: ツアー数（1 ≦ D ≦ 30 )
                // W:負担の合計の最大値 (0 ≦ W ≦ 50 )
                // X:ツアー期間中ライブを同じ日に2度以上行える合計日数の上限 ( 0
                // ≦ X ≦ 5 )
int E[40][40]; // E[i][j] 地域 i で j 日目にライブを行うことで期待される利益 ( 0
               // ≦ E[i][j] ≦ 1000)
int F[40][40]; // F[i][j] 地域 i で j 日目にライブを行うことで掛かる負担 ( 0 ≦
               // F[i][j] ≦ 10 )
vector<int> G; // 同じ日にライブを行える地域の取り方の状態
int dp[32][1 << 5][51][8]; // dp[日時][地域の取り方の状態][負担の合計][2度行える合計数]
                           // := 利益の最大値
int CC; // 同じ日にライブを行える地域の取り方の状態数

int res; // 利益の最大値を格納

void dfs(int day, int status, int benefit, int tired, int remain) {

  if (day == D) {
    res = max(res, benefit);
    return;
  } // end if

  int ans;
  rep(i, CC) {
    if (((G[i] | status) & ~status) ==
        G[i]) { // G[i] と status が重なっていない
      int connect = (__builtin_popcount(G[i]) > 1);
      if (remain == 0 && connect)
        continue;
      int curr_tired = 0;
      int curr_benefit = 0;
      rep(j, C) {
        if (G[i] & (1 << j)) {
          curr_tired += F[day][j];
          curr_benefit += E[day][j];
        } // end if
      }   // end rep
      if (tired + curr_tired > W)
        continue;
      dfs(day + 1, status | G[i], curr_benefit + benefit, tired + curr_tired,
          remain - connect);
    } // end if
  }   // end for

  //	return ans;
}

// ツアーにおける地域の可能な状態を作成する
void calc_status(int C) {
  G.clear();
  G.push_back(0); // この日はステージはなし
  for (int i = 1; i <= C; i++) {
    int curr = (1 << C) - 1;
    curr -= (1 << (i - 1)) - 1;
    for (int j = 1; j <= i; j++) {
      G.push_back(curr);
      curr >>= 1;
    } // end for
  }   // end for

  CC = G.size();
}

int main() {
  ios_base::sync_with_stdio(0);

  while (cin >> C >> D >> W >> X, C) {
    memset(E, 0, sizeof(E));
    memset(F, 0, sizeof(F));

    rep(i, C) rep(j, D) cin >>
        E[j][i]; // 行を日、列を地域とした方が処理しやすい
    rep(i, C) rep(j, D) cin >> F[j][i]; // よって直感的ではないので、注意。

    calc_status(C);
    res = 0;
    dfs(0, 0, 0, 0, X);
    cout << res << endl;
  } // end while

  return 0;
}