Problem p00766 (C++)

Buggy submission (status: Memory Limit Exceeded):
#include <algorithm>
#include <complex>
#include <cstring>
#include <iostream>
#include <queue>
#include <string>
#include <vector>
using namespace std;

int dx[] = {-1, 0, 1, 0, -1, 0, 1, 0};
int dy[] = {0, -1, 0, -1, 0, 1, 0, 1};

int nx[] = {0, 1, 0, 1};
int ny[] = {0, 0, 1, 1};

typedef complex<double> point;
struct line : public vector<point> {
  line() {}
  line(const point &a, const point &b) {
    push_back(a);
    push_back(b);
  }
};

namespace std {
bool operator<(const point &a, const point &b) {
  return a.real() != b.real() ? a.real() < b.real() : a.imag() < b.imag();
}
} // namespace std

const double eps = 1e-10;
double dot(const point &a, const point &b) { return (a * conj(b)).real(); }
double cross(const point &a, const point &b) { return (conj(a) * b).imag(); }
point unit(const point &v) { return v / abs(v); }
point vec(const line &l) { return l[1] - l[0]; }

int ccw(const point &a, const point &b, const point &c) {
  point u = b - a, v = c - a;
  if (cross(u, v) > 0)
    return +1;
  if (cross(u, v) < 0)
    return -1;
  if (dot(u, v) < 0)
    return +2;
  if (norm(u) < norm(v))
    return -2;
  return 0;
}

int ccw(const line &s, const point &p) { return ccw(s[0], s[1], p); }

bool contain(const line &s, const line &t) {
  return abs(s[0] - t[0]) < eps || abs(s[0] - t[1]) < eps ||
         abs(s[1] - t[0]) < eps || abs(s[1] - t[1]) < eps;
}

bool intersectSS(const line &s, const line &t) {
  return ccw(s, t[0]) * ccw(s, t[1]) <= 0 && ccw(t, s[0]) * ccw(t, s[1]) <= 0;
}

typedef vector<vector<int>> Graph;

int flow[5500][5500];

bool dfs(int p, int T, Graph &graph, vector<int> &level,
         vector<bool> &finished) {
  if (p == T)
    return true;
  if (finished[p])
    return false;

  finished[p] = true;

  for (int i = 0; i < graph[p].size(); i++) {
    int next = graph[p][i];
    if (level[p] >= level[next])
      continue;
    if (flow[p][next])
      continue;

    if (dfs(next, T, graph, level, finished)) {
      finished[p] = false;
      flow[p][next] += 1;
      flow[next][p] -= 1;
      return true;
    }
  }

  return false;
}

int dinic(int S, int T, Graph &graph) {
  bool end = false;
  int total = 0;
  while (!end) {
    end = true;
    vector<int> level(graph.size(), -1);
    level[S] = 0;

    queue<int> q;
    q.push(S);
    while (!q.empty()) {
      int n = q.front();
      q.pop();
      for (int i = 0; i < graph[n].size(); i++) {
        int next = graph[n][i];
        if (level[next] != -1)
          continue;
        if (flow[n][next])
          continue;
        level[next] = level[n] + 1;
        q.push(next);
      }
    }

    if (level[T] == -1)
      break;

    vector<bool> finished(graph.size());
    while (dfs(S, T, graph, level, finished)) {
      total++;
      end = false;
    }
  }

  return total;
}

void add_edge(int s, int d, Graph &g) {
  g[s].push_back(d);
  g[d].push_back(s);

  flow[s][d] = 0;
  flow[d][s] = 1;
}

int main() {
  int H, W;
  while (cin >> H >> W, (H || W)) {
    vector<string> choco(H);
    for (int i = 0; i < H; ++i) {
      cin >> choco[i];
    }

    int N = 0;
    vector<vector<int>> vert(W + 1), hori(H + 1);
    for (int i = 0; i < H; i++)
      for (int j = 0; j < W; j++) {
        if (choco[i][j] != '.')
          continue;
        for (int k = 0; k < 4; k++) {
          bool ok = true;
          for (int l = 0; l < 2; l++) {
            int nx = j + dx[2 * k + l];
            int ny = i + dy[2 * k + l];
            if (nx < 0 || ny < 0 || nx >= W || ny >= H) {
              ok = false;
              break;
            }

            if (choco[ny][nx] != '#') {
              ok = false;
              break;
            }
          }

          if (ok) {
            hori[i + ny[k]].push_back(j + nx[k]);
            vert[j + nx[k]].push_back(i + ny[k]);
            N++;
          }
        }
      }

    for (int i = 0; i < H + 1; i++) {
      sort(hori[i].begin(), hori[i].end());
    }

    for (int i = 0; i < W + 1; i++)
      sort(vert[i].begin(), vert[i].end());

    vector<line> l, r;
    for (int i = 0; i < H + 1; i++) {
      int S = hori[i].size();
      for (int j = 0; j < S - 1; j++) {
        bool c[2] = {0};
        for (int k = hori[i][j]; k < hori[i][j + 1]; k++) {
          if (choco[i - 1][k] != '#')
            c[0] = true;
          if (choco[i][k] != '#')
            c[1] = true;
        }

        if (!c[0] && !c[1]) {
          l.push_back(line(point(hori[i][j], i), point(hori[i][j + 1], i)));
        }
      }
    }

    for (int i = 0; i < W + 1; i++) {
      int S = vert[i].size();
      for (int j = 0; j < S - 1; j++) {
        bool c[2] = {0};
        for (int k = vert[i][j]; k < vert[i][j + 1]; k++) {
          if (choco[k][i - 1] != '#')
            c[0] = true;
          if (choco[k][i] != '#')
            c[1] = true;
        }

        if (!c[0] && !c[1]) {
          r.push_back(line(point(i, vert[i][j]), point(i, vert[i][j + 1])));
        }
      }
    }

    memset(flow, 0, sizeof(flow));

    int M = l.size() + r.size();

    Graph graph(M + 2);
    for (int i = 0; i < l.size(); i++)
      add_edge(M, i, graph);

    for (int i = 0; i < r.size(); i++)
      add_edge(i + l.size(), M + 1, graph);

    for (int i = 0; i < l.size(); i++)
      for (int j = 0; j < r.size(); j++) {
        if (intersectSS(l[i], r[j])) {
          int u = i, v = j + l.size();
          add_edge(u, v, graph);
        }
      }

    cout << N - (M - dinic(M, M + 1, graph)) + 1 << endl;
  }
  return 0;
}

Fixed submission:
#include <algorithm>
#include <complex>
#include <cstring>
#include <iostream>
#include <queue>
#include <string>
#include <vector>
using namespace std;

int dx[] = {-1, 0, 1, 0, -1, 0, 1, 0};
int dy[] = {0, -1, 0, -1, 0, 1, 0, 1};

int nx[] = {0, 1, 0, 1};
int ny[] = {0, 0, 1, 1};

typedef complex<double> point;
struct line : public vector<point> {
  line() {}
  line(const point &a, const point &b) {
    push_back(a);
    push_back(b);
  }
};

namespace std {
bool operator<(const point &a, const point &b) {
  return a.real() != b.real() ? a.real() < b.real() : a.imag() < b.imag();
}
} // namespace std

const double eps = 1e-10;
double dot(const point &a, const point &b) { return (a * conj(b)).real(); }
double cross(const point &a, const point &b) { return (conj(a) * b).imag(); }
point unit(const point &v) { return v / abs(v); }
point vec(const line &l) { return l[1] - l[0]; }

int ccw(const point &a, const point &b, const point &c) {
  point u = b - a, v = c - a;
  if (cross(u, v) > 0)
    return +1;
  if (cross(u, v) < 0)
    return -1;
  if (dot(u, v) < 0)
    return +2;
  if (norm(u) < norm(v))
    return -2;
  return 0;
}

int ccw(const line &s, const point &p) { return ccw(s[0], s[1], p); }

bool contain(const line &s, const line &t) {
  return abs(s[0] - t[0]) < eps || abs(s[0] - t[1]) < eps ||
         abs(s[1] - t[0]) < eps || abs(s[1] - t[1]) < eps;
}

bool intersectSS(const line &s, const line &t) {
  return ccw(s, t[0]) * ccw(s, t[1]) <= 0 && ccw(t, s[0]) * ccw(t, s[1]) <= 0;
}

typedef vector<vector<int>> Graph;

char flow[5500][5500];

bool dfs(int p, int T, Graph &graph, vector<int> &level,
         vector<bool> &finished) {
  if (p == T)
    return true;
  if (finished[p])
    return false;

  finished[p] = true;

  for (int i = 0; i < graph[p].size(); i++) {
    int next = graph[p][i];
    if (level[p] >= level[next])
      continue;
    if (flow[p][next])
      continue;

    if (dfs(next, T, graph, level, finished)) {
      finished[p] = false;
      flow[p][next] += 1;
      flow[next][p] -= 1;
      return true;
    }
  }

  return false;
}

int dinic(int S, int T, Graph &graph) {
  bool end = false;
  int total = 0;
  while (!end) {
    end = true;
    vector<int> level(graph.size(), -1);
    level[S] = 0;

    queue<int> q;
    q.push(S);
    while (!q.empty()) {
      int n = q.front();
      q.pop();
      for (int i = 0; i < graph[n].size(); i++) {
        int next = graph[n][i];
        if (level[next] != -1)
          continue;
        if (flow[n][next])
          continue;
        level[next] = level[n] + 1;
        q.push(next);
      }
    }

    if (level[T] == -1)
      break;

    vector<bool> finished(graph.size());
    while (dfs(S, T, graph, level, finished)) {
      total++;
      end = false;
    }
  }

  return total;
}

void add_edge(int s, int d, Graph &g) {
  g[s].push_back(d);
  g[d].push_back(s);

  flow[s][d] = 0;
  flow[d][s] = 1;
}

int main() {
  int H, W;
  while (cin >> H >> W, (H || W)) {
    vector<string> choco(H);
    for (int i = 0; i < H; ++i) {
      cin >> choco[i];
    }

    int N = 0;
    vector<vector<int>> vert(W + 1), hori(H + 1);
    for (int i = 0; i < H; i++)
      for (int j = 0; j < W; j++) {
        if (choco[i][j] != '.')
          continue;
        for (int k = 0; k < 4; k++) {
          bool ok = true;
          for (int l = 0; l < 2; l++) {
            int nx = j + dx[2 * k + l];
            int ny = i + dy[2 * k + l];
            if (nx < 0 || ny < 0 || nx >= W || ny >= H) {
              ok = false;
              break;
            }

            if (choco[ny][nx] != '#') {
              ok = false;
              break;
            }
          }

          if (ok) {
            hori[i + ny[k]].push_back(j + nx[k]);
            vert[j + nx[k]].push_back(i + ny[k]);
            N++;
          }
        }
      }

    for (int i = 0; i < H + 1; i++) {
      sort(hori[i].begin(), hori[i].end());
    }

    for (int i = 0; i < W + 1; i++)
      sort(vert[i].begin(), vert[i].end());

    vector<line> l, r;
    for (int i = 0; i < H + 1; i++) {
      int S = hori[i].size();
      for (int j = 0; j < S - 1; j++) {
        bool c[2] = {0};
        for (int k = hori[i][j]; k < hori[i][j + 1]; k++) {
          if (choco[i - 1][k] != '#')
            c[0] = true;
          if (choco[i][k] != '#')
            c[1] = true;
        }

        if (!c[0] && !c[1]) {
          l.push_back(line(point(hori[i][j], i), point(hori[i][j + 1], i)));
        }
      }
    }

    for (int i = 0; i < W + 1; i++) {
      int S = vert[i].size();
      for (int j = 0; j < S - 1; j++) {
        bool c[2] = {0};
        for (int k = vert[i][j]; k < vert[i][j + 1]; k++) {
          if (choco[k][i - 1] != '#')
            c[0] = true;
          if (choco[k][i] != '#')
            c[1] = true;
        }

        if (!c[0] && !c[1]) {
          r.push_back(line(point(i, vert[i][j]), point(i, vert[i][j + 1])));
        }
      }
    }

    memset(flow, 0, sizeof(flow));

    int M = l.size() + r.size();

    Graph graph(M + 2);
    for (int i = 0; i < l.size(); i++)
      add_edge(M, i, graph);

    for (int i = 0; i < r.size(); i++)
      add_edge(i + l.size(), M + 1, graph);

    for (int i = 0; i < l.size(); i++)
      for (int j = 0; j < r.size(); j++) {
        if (intersectSS(l[i], r[j])) {
          int u = i, v = j + l.size();
          add_edge(u, v, graph);
        }
      }

    cout << N - (M - dinic(M, M + 1, graph)) + 1 << endl;
  }
  return 0;
}