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

// 基本テンプレート

#include <algorithm>
#include <cassert>
#include <cfloat>
#include <climits>
#include <cmath>
#include <complex>
#include <cstdio>
#include <cstring>
#include <ctime>
#include <deque>
#include <fstream>
#include <functional>
#include <iomanip>
#include <iostream>
#include <limits>
#include <list>
#include <map>
#include <numeric>
#include <queue>
#include <set>
#include <stack>
#include <string>
#include <utility>
#include <vector>
using namespace std;

#define rep(i, a, n) for (int(i) = (a); (i) < (n); (i)++)
#define repq(i, a, n) for (int(i) = (a); (i) <= (n); (i)++)
#define repr(i, a, n) for (int(i) = (a); (i) >= (n); (i)--)
#define debug(...) fprintf(stderr, __VA_ARGS__)
#define int long long int

template <typename T> void chmax(T &a, T b) { a = max(a, b); }
template <typename T> void chmin(T &a, T b) { a = min(a, b); }
template <typename T> void chadd(T &a, T b) { a = a + b; }

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

int dx[] = {0, 0, 1, -1};
int dy[] = {1, -1, 0, 0};
const ll INF = 1001001001001001LL;
const ll MOD = 1000000007LL;

int rec[210][210], dp[6600];
int memo[6600];

int D, K, L, M, N, P;
int c[10][10], r[210][10], t[210][10];

// Ford-Fulkerson 法による 最大流 O( F |E| )
// Bellman-Ford 法による 最小費用流 O( F |V| |E| )
// Verified: AOJ GRL_6_A (Maximum Flow)

// 行き先と容量と逆辺のインデックスを記録する構造体
// 通常のグラフの辺の構造体と異なるため注意

// 最小費用流はもう少し速くできるので、改良しましょう
// → ダイクストラが使えるようにポテンシャルを導入しよう

template <typename T> struct Edge {
  int to;
  T cap, cost;
  int rev;
  Edge(int t, T c, int r) : to(t), cap(c), rev(r) {}
  Edge(int t, T ca, T co, int r) : to(t), cap(ca), cost(co), rev(r) {}
};

template <typename T> using Graph = vector<vector<Edge<T>>>;

template <typename T> struct Elem {
  int pos;
  T cost;
  Elem() {}
  Elem(int a, T b) : pos(a), cost(b) {}
  bool operator<(const Elem &e) const { return cost > e.cost; }
};

template <typename T> struct Flow {
  vector<vector<Edge<T>>> G;
  const T MAXC = 1 << 30;
  int n;
  vector<bool> used;
  vector<int> prevv, preve, dist, pot;
  Flow(int _n)
      : G(_n), n(_n), used(_n, false), prevv(n), preve(n), dist(n, MAXC),
        pot(n) {}

  // G[e.to][e.rev] で逆辺を操作できる
  void add_edge(int from, int to, T cap) {
    G[from].push_back(Edge<T>(to, cap, G[to].size()));
    G[to].push_back(Edge<T>(from, 0, G[from].size() - 1));
  }
  void add_edge(int from, int to, T cap, T cost) {
    G[from].push_back(Edge<T>(to, cap, cost, G[to].size()));
    G[to].push_back(Edge<T>(from, 0, -cost, G[from].size() - 1));
  }

  T dfs(int v, int t, T f) {
    if (v == t)
      return f;
    used[v] = true;
    for (int i = 0; i < G[v].size(); i++) {
      Edge<T> &e = G[v][i];
      if (!used[e.to] && e.cap > 0) {
        T d = dfs(e.to, t, min(f, e.cap));
        if (d > 0) {
          e.cap -= d;
          G[e.to][e.rev].cap += d;
          return d;
        }
      }
    }
    return 0;
  }

  T max_flow(int s, int t) {
    T flow = 0;
    while (1) {
      fill(used.begin(), used.end(), false);
      T f = dfs(s, t, INF);
      if (f == 0)
        return flow;
      flow += f;
    }
  }

  /*
  T mincost_flow(int s, int t, T f) {
      T res = 0;
      T ma = MAXC;
      while(f > 0) {
          fill(dist.begin(), dist.end(), ma);
          dist[s] = 0;
          bool update = true;
          while(update) {
              update = false;
              for(int v = 0; v < n; v++) {
                  if(dist[v] == ma) continue;
                  for(int i=0; i<G[v].size(); i++) {
                      Edge<T> &e = G[v][i];
                      if(e.cap>0 && dist[e.to] > dist[v] + e.cost) {
                          dist[e.to] = dist[v] + e.cost;
                          prevv[e.to] = v;
                          preve[e.to] = i;
                          update = true;
                      }
                  }
              }
          }

          if(dist[t] == ma) return -1;
          T d = f;
          for(int v = t; v != s; v = prevv[v]) {
              d = min(d, G[prevv[v]][preve[v]].cap);
          }
          f -= d;
          res += d * dist[t];
          for(int v = t; v != s; v = prevv[v]) {
              Edge<T> &e = G[prevv[v]][preve[v]];
              e.cap -= d;
              G[v][e.rev].cap += d;
          }
      }
      return res;
  }
  */

  T mincost_flow(int s, int t, T f) {
    T res = 0;
    fill(pot.begin(), pot.end(), 0);
    while (f > 0) {
      priority_queue<Elem<T>> que;
      fill(dist.begin(), dist.end(), INF);

      dist[s] = 0;
      que.push(Elem<T>(s, 0));

      while (que.size()) {
        Elem<T> cur = que.top();
        que.pop();
        int v = cur.pos;
        if (dist[v] < cur.cost)
          continue;
        for (size_t i = 0; i < G[v].size(); i++) {
          Edge<T> &e = G[v][i];
          if (e.cap > 0 && dist[e.to] > dist[v] + e.cost + pot[v] - pot[e.to]) {
            dist[e.to] = dist[v] + e.cost + pot[v] - pot[e.to];
            prevv[e.to] = v;
            preve[e.to] = i;
            que.push(Elem<T>(e.to, dist[e.to]));
          }
        }
      }

      if (dist[t] == INF)
        return -1;
      for (int v = 0; v < n; v++)
        pot[v] += dist[v];

      T d = f;
      for (int v = t; v != s; v = prevv[v]) {
        d = min(d, G[prevv[v]][preve[v]].cap);
      }
      f -= d;
      res += d * pot[t];

      for (int v = t; v != s; v = prevv[v]) {
        Edge<T> &e = G[prevv[v]][preve[v]];
        e.cap -= d;
        G[v][e.rev].cap += d;
      }
    }
    return res;
  }
};

string int2tri(int val) {
  string res = "";
  for (int i = 0; i < K; i++) {
    res += (char)('0' + (val % 3));
    val /= 3;
  }
  return res;
}

int tri2int(string s) {
  reverse(s.begin(), s.end());
  int res = 0;
  for (size_t i = 0; i < s.length(); i++) {
    res *= 3;
    res += (s[i] - '0');
  }
  return res;
}

signed main() {
  while (cin >> D >> K >> L, D || K || L) {
    int pow3 = 1;
    for (int i = 0; i < K; i++)
      pow3 *= 3;

    for (int i = 0; i < D; i++) {
      for (int j = 0; j < K; j++) {
        cin >> c[i][j];
      }
    }
    cin >> M >> N >> P;
    for (int i = 0; i < M; i++) {
      for (int j = 0; j < K; j++) {
        cin >> r[i][j];
      }
    }
    for (int i = 0; i < P + 1; i++) {
      for (int j = 0; j < K; j++) {
        if (i < P)
          cin >> t[i][j];
        else
          t[i][j] = 0;
      }
    }
    P++;

    fill(memo, memo + 6600, INF);
    fill(dp, dp + 6600, INF);
    memo[0] = 0;
    for (int d = 0; d < D; d++) {
      for (int j = 0; j < L; j++) {
        for (int x = pow3 - 1; x >= 0; x--) {
          int cost = memo[x];
          string s = int2tri(x);
          for (int i = 0; i < K; i++) {
            if (s[i] == '2')
              continue;
            s[i]++;
            int ncost = cost + c[d][i], nx = tri2int(s);
            if (memo[nx] > ncost) {
              memo[nx] = ncost;
            }
            s[i]--;
          }
        }
      }
    }

    for (int j = 0; j <= L; j++) {
      for (int x = 0; x < pow3; x++) {
        int cost = memo[x];
        chmin(dp[x], cost);
      }
    }

    /*
    for(auto x : dp) {
        fprintf(stderr, "dp[%s] = %lld\\n", x.first.c_str(), x.second);
    }
    */

    for (int i = 0; i < M; i++) {
      for (int j = 0; j < P; j++) {
        bool ok = true;
        string target = "";
        for (int k = 0; k < K; k++) {
          if (r[i][k] < t[j][k])
            ok = false;
          target += (char)('0' + r[i][k] - t[j][k]);
        }

        if (ok) {
          int bit = tri2int(target);
          rec[i][j] = dp[bit];
        } else {
          rec[i][j] = INF;
        }
      }
    }

    Flow<int> fl(M + P + 1);
    int source = M + P - 1, sink = source + 1;
    for (int i = 0; i < M; i++) {
      fl.add_edge(source, i, 1, 0);
    }
    for (int i = 0; i < P - 1; i++) {
      fl.add_edge(M + i, sink, 1, 0);
    }

    for (int i = 0; i < M; i++) {
      for (int j = 0; j < P; j++) {
        if (rec[i][j] == INF)
          continue;
        if (j == P - 1)
          fl.add_edge(i, sink, 1, rec[i][j]);
        else
          fl.add_edge(i, M + j, 1, rec[i][j]);
      }
    }

    int ans = fl.mincost_flow(source, sink, N);
    cout << ans << endl;
  }
  return 0;
}


Error: TLE

Fixed submission:

// 基本テンプレート

#include <algorithm>
#include <cassert>
#include <cfloat>
#include <climits>
#include <cmath>
#include <complex>
#include <cstdio>
#include <cstring>
#include <ctime>
#include <deque>
#include <fstream>
#include <functional>
#include <iomanip>
#include <iostream>
#include <limits>
#include <list>
#include <map>
#include <numeric>
#include <queue>
#include <set>
#include <stack>
#include <string>
#include <utility>
#include <vector>
using namespace std;

#define rep(i, a, n) for (int(i) = (a); (i) < (n); (i)++)
#define repq(i, a, n) for (int(i) = (a); (i) <= (n); (i)++)
#define repr(i, a, n) for (int(i) = (a); (i) >= (n); (i)--)
#define debug(...) fprintf(stderr, __VA_ARGS__)
#define int long long int

template <typename T> void chmax(T &a, T b) { a = max(a, b); }
template <typename T> void chmin(T &a, T b) { a = min(a, b); }
template <typename T> void chadd(T &a, T b) { a = a + b; }

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

int dx[] = {0, 0, 1, -1};
int dy[] = {1, -1, 0, 0};
const ll INF = 1001001001001001LL;
const ll MOD = 1000000007LL;

int rec[210][210], dp[6600];
int memo[2][9][9][6600];

int D, K, L, M, N, P;
int c[10][10], r[210][10], t[210][10];

// Ford-Fulkerson 法による 最大流 O( F |E| )
// Bellman-Ford 法による 最小費用流 O( F |V| |E| )
// Verified: AOJ GRL_6_A (Maximum Flow)

// 行き先と容量と逆辺のインデックスを記録する構造体
// 通常のグラフの辺の構造体と異なるため注意

// 最小費用流はもう少し速くできるので、改良しましょう
// → ダイクストラが使えるようにポテンシャルを導入しよう

template <typename T> struct Edge {
  int to;
  T cap, cost;
  int rev;
  Edge(int t, T c, int r) : to(t), cap(c), rev(r) {}
  Edge(int t, T ca, T co, int r) : to(t), cap(ca), cost(co), rev(r) {}
};

template <typename T> using Graph = vector<vector<Edge<T>>>;

template <typename T> struct Elem {
  int pos;
  T cost;
  Elem() {}
  Elem(int a, T b) : pos(a), cost(b) {}
  bool operator<(const Elem &e) const { return cost > e.cost; }
};

template <typename T> struct Flow {
  vector<vector<Edge<T>>> G;
  const T MAXC = 1 << 30;
  int n;
  vector<bool> used;
  vector<int> prevv, preve, dist, pot;
  Flow(int _n)
      : G(_n), n(_n), used(_n, false), prevv(n), preve(n), dist(n, MAXC),
        pot(n) {}

  // G[e.to][e.rev] で逆辺を操作できる
  void add_edge(int from, int to, T cap) {
    G[from].push_back(Edge<T>(to, cap, G[to].size()));
    G[to].push_back(Edge<T>(from, 0, G[from].size() - 1));
  }
  void add_edge(int from, int to, T cap, T cost) {
    G[from].push_back(Edge<T>(to, cap, cost, G[to].size()));
    G[to].push_back(Edge<T>(from, 0, -cost, G[from].size() - 1));
  }

  T dfs(int v, int t, T f) {
    if (v == t)
      return f;
    used[v] = true;
    for (int i = 0; i < G[v].size(); i++) {
      Edge<T> &e = G[v][i];
      if (!used[e.to] && e.cap > 0) {
        T d = dfs(e.to, t, min(f, e.cap));
        if (d > 0) {
          e.cap -= d;
          G[e.to][e.rev].cap += d;
          return d;
        }
      }
    }
    return 0;
  }

  T max_flow(int s, int t) {
    T flow = 0;
    while (1) {
      fill(used.begin(), used.end(), false);
      T f = dfs(s, t, INF);
      if (f == 0)
        return flow;
      flow += f;
    }
  }

  /*
  T mincost_flow(int s, int t, T f) {
      T res = 0;
      T ma = MAXC;
      while(f > 0) {
          fill(dist.begin(), dist.end(), ma);
          dist[s] = 0;
          bool update = true;
          while(update) {
              update = false;
              for(int v = 0; v < n; v++) {
                  if(dist[v] == ma) continue;
                  for(int i=0; i<G[v].size(); i++) {
                      Edge<T> &e = G[v][i];
                      if(e.cap>0 && dist[e.to] > dist[v] + e.cost) {
                          dist[e.to] = dist[v] + e.cost;
                          prevv[e.to] = v;
                          preve[e.to] = i;
                          update = true;
                      }
                  }
              }
          }

          if(dist[t] == ma) return -1;
          T d = f;
          for(int v = t; v != s; v = prevv[v]) {
              d = min(d, G[prevv[v]][preve[v]].cap);
          }
          f -= d;
          res += d * dist[t];
          for(int v = t; v != s; v = prevv[v]) {
              Edge<T> &e = G[prevv[v]][preve[v]];
              e.cap -= d;
              G[v][e.rev].cap += d;
          }
      }
      return res;
  }
  */

  T mincost_flow(int s, int t, T f) {
    T res = 0;
    fill(pot.begin(), pot.end(), 0);
    while (f > 0) {
      priority_queue<Elem<T>> que;
      fill(dist.begin(), dist.end(), INF);

      dist[s] = 0;
      que.push(Elem<T>(s, 0));

      while (que.size()) {
        Elem<T> cur = que.top();
        que.pop();
        int v = cur.pos;
        if (dist[v] < cur.cost)
          continue;
        for (size_t i = 0; i < G[v].size(); i++) {
          Edge<T> &e = G[v][i];
          if (e.cap > 0 && dist[e.to] > dist[v] + e.cost + pot[v] - pot[e.to]) {
            dist[e.to] = dist[v] + e.cost + pot[v] - pot[e.to];
            prevv[e.to] = v;
            preve[e.to] = i;
            que.push(Elem<T>(e.to, dist[e.to]));
          }
        }
      }

      if (dist[t] == INF)
        return -1;
      for (int v = 0; v < n; v++)
        pot[v] += dist[v];

      T d = f;
      for (int v = t; v != s; v = prevv[v]) {
        d = min(d, G[prevv[v]][preve[v]].cap);
      }
      f -= d;
      res += d * pot[t];

      for (int v = t; v != s; v = prevv[v]) {
        Edge<T> &e = G[prevv[v]][preve[v]];
        e.cap -= d;
        G[v][e.rev].cap += d;
      }
    }
    return res;
  }
};

string int2tri(int val) {
  string res = "";
  for (int i = 0; i < K; i++) {
    res += (char)('0' + (val % 3));
    val /= 3;
  }
  return res;
}

int tri2int(string s) {
  reverse(s.begin(), s.end());
  int res = 0;
  for (size_t i = 0; i < s.length(); i++) {
    res *= 3;
    res += (s[i] - '0');
  }
  return res;
}

signed main() {
  while (cin >> D >> K >> L, D || K || L) {
    int pow3 = 1;
    for (int i = 0; i < K; i++)
      pow3 *= 3;

    for (int i = 0; i < D; i++) {
      for (int j = 0; j < K; j++) {
        cin >> c[i][j];
      }
    }
    cin >> M >> N >> P;
    for (int i = 0; i < M; i++) {
      for (int j = 0; j < K; j++) {
        cin >> r[i][j];
      }
    }
    for (int i = 0; i < P + 1; i++) {
      for (int j = 0; j < K; j++) {
        if (i < P)
          cin >> t[i][j];
        else
          t[i][j] = 0;
      }
    }
    P++;

    fill(memo[0][0][0], memo[2][0][0], INF);
    fill(dp, dp + 6600, INF);
    memo[0][0][0][0] = 0;
    for (int d = 0; d < D; d++) {
      int mod = d % 2, nxt = 1 - mod;
      for (int i = 0; i < K; i++) {
        for (int j = 0; j <= L; j++) {
          for (int x = 0; x < pow3; x++) {
            int cost = memo[mod][i][j][x];
            string s = int2tri(x);

            int cur = s[i] - '0';
            for (int a = 0; a <= 2; a++) {
              if (cur + a > 2)
                continue;
              if (j + a > L)
                continue;

              string ns = s;
              ns[i] += a;

              int ncost = cost + a * c[d][i];
              int nx = tri2int(ns);
              if (memo[mod][i + 1][j + a][nx] > ncost) {
                memo[mod][i + 1][j + a][nx] = ncost;
              }
            }
          }
        }
      }

      fill(memo[nxt][0][0], memo[nxt + 1][0][0], INF);
      for (int j = 0; j <= L; j++) {
        for (int x = 0; x < pow3; x++) {
          // fprintf(stderr, "memo[%lld][%lld][%lld][%s] = %lld", d, K, j,
          // int2tri(x).c_str(), memo[mod][K][j][x]);
          int cost = memo[mod][K][j][x];
          chmin(memo[nxt][0][0][x], cost);
          // fprintf(stderr, " -> %lld\\n", memo[nxt][0][0][x]);
        }
      }
    }

    for (int j = 0; j <= L; j++) {
      for (int x = 0; x < pow3; x++) {
        int cost = memo[D % 2][0][0][x];
        chmin(dp[x], cost);
      }
    }

    /*
    for(auto x : dp) {
        fprintf(stderr, "dp[%s] = %lld\\n", x.first.c_str(), x.second);
    }
    */

    for (int i = 0; i < M; i++) {
      for (int j = 0; j < P; j++) {
        bool ok = true;
        string target = "";
        for (int k = 0; k < K; k++) {
          if (r[i][k] < t[j][k])
            ok = false;
          target += (char)('0' + r[i][k] - t[j][k]);
        }

        if (ok) {
          int bit = tri2int(target);
          rec[i][j] = dp[bit];
        } else {
          rec[i][j] = INF;
        }
      }
    }

    Flow<int> fl(M + P + 1);
    int source = M + P - 1, sink = source + 1;
    for (int i = 0; i < M; i++) {
      fl.add_edge(source, i, 1, 0);
    }
    for (int i = 0; i < P - 1; i++) {
      fl.add_edge(M + i, sink, 1, 0);
    }

    for (int i = 0; i < M; i++) {
      for (int j = 0; j < P; j++) {
        if (rec[i][j] == INF)
          continue;
        if (j == P - 1)
          fl.add_edge(i, sink, 1, rec[i][j]);
        else
          fl.add_edge(i, M + j, 1, rec[i][j]);
      }
    }

    int ans = fl.mincost_flow(source, sink, N);
    cout << ans << endl;
  }
  return 0;
}