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

#include <bits/stdc++.h>

using namespace std;
#define pb push_back
#define all(x) x.begin(), x.end()
#define sz(x) (int)x.size()
using ll = long long;
using pii = pair<int, int>;
using ull = unsigned long long;

const int mn = 55;

namespace Min_Cost_Max_Flow {
const int INF = 0x3f3f3f3f; // INF flow
const int N = 2503;         // 最大点数
const int M = 50000;        // 最大边数
int S, T, cnt, from[N], g[N], flow;
ll d[N]; // 这里的 flow 就是最大流量
ll ans;  // 费用，即为答案
struct edge {
  int from, to, nxt, v;
  ll c;
} e[M]; // c 是价格 v 是流量
void add(int u, int v, int w, ll c) {
  e[++cnt].from = u;
  e[cnt].to = v;
  e[cnt].nxt = g[u];
  g[u] = cnt;
  e[cnt].c = c;
  e[cnt].v = w;
}

void add_edge(int u, int v, int w, ll c) {
  // printf("add_edge %d %d %d %lld\\n", u, v, w, c);
  add(u, v, w, c);
  add(v, u, 0, -c);
}

bool spfa() {
  fill_n(d, N, INF);
  d[S] = 0;
  memset(from, 0, sizeof(from));
  queue<int> q;
  q.push(S);
  while (!q.empty()) {
    int now = q.front();
    q.pop();
    for (int i = g[now]; i; i = e[i].nxt) {
      if (e[i].v && d[e[i].to] > d[now] + e[i].c) {
        d[e[i].to] = d[now] + e[i].c;
        from[e[i].to] = i;
        q.push(e[i].to);
      }
    }
  }
  return (d[T] != INF);
  // 改为return(d[T]<=0)即为最小费用可行流
}

void mcf() {
  int x = INF;
  for (int i = from[T]; i; i = from[e[i].from])
    x = min(x, e[i].v);
  flow += x;
  for (int i = from[T]; i; i = from[e[i].from]) {
    e[i].v -= x;
    e[i ^ 1].v += x;
    ans += e[i].c * x;
  }
}

void Initialize(int s, int t) { // 源点和汇点
  S = s;
  T = t;
  memset(g, 0, sizeof(g));
  memset(e, 0, sizeof(e));
  ans = flow = 0;
  cnt = 1;
}

void doit() {
  while (spfa())
    mcf();
}
} // namespace Min_Cost_Max_Flow

int n, m;
char s[mn][mn];

int getid(int x, int y) { return (x - 1) * m + y; }

int vis[mn][mn];
int to_end[mn][mn];

int head_count = 0;

void calc(int x, int y) {
  struct node {
    int x, y, t;

    bool operator<(const node &p) const { return t > p.t; }
  };
  memset(vis, 0, sizeof vis);
  queue<node> q;
  q.push({x, y, 0});
  vector<node> v;
  while (!q.empty()) {
    node u = q.front();
    q.pop();
    // printf("%d %d\\n", u.x, u.y);
    v.push_back(u);
    if (u.x < n) {
      node nxt = {u.x + 1, u.y, u.t + 1};
      if (!(vis[nxt.x][nxt.y] || s[nxt.x][nxt.y] == '#')) {
        vis[nxt.x][nxt.y] = 1;
        q.push(nxt);
      }
    }
    if (u.y < m) {
      node nxt = {u.x, u.y + 1, u.t + 1};
      if (vis[nxt.x][nxt.y] || s[nxt.x][nxt.y] == '#')
        continue;
      vis[nxt.x][nxt.y] = 1;
      q.push(nxt);
    }
  }
  sort(begin(v), end(v));

  using namespace Min_Cost_Max_Flow;
  for (int i = 0; i < v.size() && i < head_count; i++) {
    node &p = v[i];
    if (p.t == 0)
      break;
    // printf("%d %d -> %d %d : %d\\n", x, y, p.x, p.y, p.t);
    add_edge(getid(x, y), getid(p.x, p.y), 1, -p.t);
    if (!to_end[p.x][p.y]) {
      to_end[p.x][p.y] = 1;
      add_edge(getid(p.x, p.y), n * m + 1, 1, 0);
    }
  }
  if (!to_end[x][y]) {
    to_end[x][y] = 1;
    add_edge(getid(x, y), n * m + 1, 1, 0);
  }
}

int main() {
  // cin.sync_with_stdio(0);
#ifdef trote
  freopen("../1.txt", "r", stdin);
  // freopen("../2.txt", "w", stdout);
  auto bg = clock();
#endif

  using namespace Min_Cost_Max_Flow;
  scanf("%d%d", &n, &m);
  Initialize(0, n * m + 1);
  for (int i = 1; i <= n; i++) {
    scanf("%s", s[i] + 1);
  }
  for (int i = 1; i <= n; i++) {
    for (int j = 1; j <= m; j++) {
      if (s[i][j] == 'o') {
        add_edge(0, getid(i, j), 1, 0);
        head_count++;
      }
    }
  }
  for (int i = 1; i <= n; i++) {
    for (int j = 1; j <= m; j++) {
      if (s[i][j] == 'o') {
        calc(i, j);
      }
    }
  }
  doit();
  printf("%lld\\n", -ans);
}

Error: TLE

Fixed submission:

#include <bits/stdc++.h>

using namespace std;
#define pb push_back
#define all(x) x.begin(), x.end()
#define sz(x) (int)x.size()
using ll = long long;
using pii = pair<int, int>;
using ull = unsigned long long;

const int mn = 50;

namespace Min_Cost_Max_Flow {
const int INF = 0x3f3f3f3f; // INF flow
const int N = 2505;         // 最大点数
const int M = 40000;        // 最大边数
int S, T, cnt, from[N], g[N], flow;
ll d[N]; // 这里的 flow 就是最大流量
ll ans;  // 费用，即为答案
struct edge {
  int from, to, nxt, v;
  ll c;
} e[M]; // c 是价格 v 是流量
void add(int u, int v, int w, ll c) {
  e[++cnt].from = u;
  e[cnt].to = v;
  e[cnt].nxt = g[u];
  g[u] = cnt;
  e[cnt].c = c;
  e[cnt].v = w;
}

void add_edge(int u, int v, int w, ll c) {
  // printf("add_edge %d %d %d %lld\\n",u,v,w,c);
  add(u, v, w, c);
  add(v, u, 0, -c);
}

bool spfa() {
  fill_n(d, N, INF);
  d[S] = 0;
  memset(from, 0, sizeof(from));
  queue<int> q;
  q.push(S);
  while (!q.empty()) {
    int now = q.front();
    q.pop();
    for (int i = g[now]; i; i = e[i].nxt) {
      if (e[i].v && d[e[i].to] > d[now] + e[i].c) {
        d[e[i].to] = d[now] + e[i].c;
        from[e[i].to] = i;
        q.push(e[i].to);
      }
    }
  }
  return (d[T] != INF);
  // 改为return(d[T]<=0)即为最小费用可行流
}

void mcf() {
  int x = INF;
  for (int i = from[T]; i; i = from[e[i].from])
    x = min(x, e[i].v);
  flow += x;
  for (int i = from[T]; i; i = from[e[i].from]) {
    e[i].v -= x;
    e[i ^ 1].v += x;
    ans += e[i].c * x;
  }
}

void Initialize(int s, int t) { // 源点和汇点
  S = s;
  T = t;
  memset(g, 0, sizeof(g));
  memset(e, 0, sizeof(e));
  ans = flow = 0;
  cnt = 1;
}

void doit() {
  while (spfa())
    mcf();
}
} // namespace Min_Cost_Max_Flow

int n, m;
char s[mn][mn];

int getid(int x, int y) { return (x - 1) * m + y; }

int main() {
  // cin.sync_with_stdio(0);
#ifdef trote
  freopen("../1.txt", "r", stdin);
  // freopen("../2.txt", "w", stdout);
  auto bg = clock();
#endif

  using namespace Min_Cost_Max_Flow;
  scanf("%d%d", &n, &m);
  Initialize(0, n * m + 1);
  for (int i = 1; i <= n; i++) {
    scanf("%s", s[i] + 1);
  }
  for (int i = 1; i <= n; i++) {
    for (int j = 1; j <= m; j++) {
      if (s[i][j] == '#')
        continue;
      if (s[i][j] == 'o') {
        add_edge(0, getid(i, j), 1, 0);
      }
      if (i < n && s[i + 1][j] != '#') {
        add_edge(getid(i, j), getid(i + 1, j), INF, -1);
      }
      if (j < m && s[i][j + 1] != '#') {
        add_edge(getid(i, j), getid(i, j + 1), INF, -1);
      }
      add_edge(getid(i, j), n * m + 1, 1, 0);
    }
  }
  doit();
  printf("%lld\\n", -ans);
}