Problem p01187 (C++) — buggy submission, verdict: Runtime Error

#include <algorithm>
#include <cfloat>
#include <cmath>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <stack>
#include <stdio.h>
#include <string>
#include <time.h>
#include <vector>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;

#define NUM 3000

// 辺を表す構造体(行先、容量、逆辺のインデックス)
struct Edge {
  Edge(int arg_to, int arg_capacity, int arg_rev_index) {
    to = arg_to;
    capacity = arg_capacity;
    rev_index = arg_rev_index;
  }
  int to, capacity, rev_index;
};

int V, E;
int N;
map<int, int> MAP;
vector<Edge> G[NUM];   // グラフの隣接リスト表現
int dist[NUM];         // sourceからの距離
int cheked_index[NUM]; // どこまで調べ終わったか

// fromからtoへ向かう容量capacityの辺をグラフに追加する
void add_edge(int from, int to, int capacity) {
  G[from].push_back(Edge(to, capacity, G[to].size()));
  G[to].push_back(Edge(from, 0, G[from].size() - 1)); // 逆辺の、初期容量は0
}

// sourceからの最短距離をBFSで計算する
void bfs(int source) {
  for (int i = 0; i < V; i++)
    dist[i] = -1;
  queue<int> Q;
  dist[source] = 0;
  Q.push(source);

  while (!Q.empty()) {
    int node_id = Q.front();
    Q.pop();
    for (int i = 0; i < G[node_id].size(); i++) {
      Edge &e = G[node_id][i];
      if (e.capacity > 0 &&
          dist[e.to] < 0) { // 辺の容量が正で、かつエッジの行先に未訪問の場合
        dist[e.to] = dist[node_id] + 1;
        Q.push(e.to);
      }
    }
  }
}

// 増加パスをDFSで探す
int dfs(int node_id, int sink, int flow) {
  if (node_id == sink)
    return flow; // 終点についたらflowをreturn

  for (int &i = cheked_index[node_id]; i < G[node_id].size();
       i++) { // node_idから出ているエッジを調査
    Edge &e = G[node_id][i];
    if (e.capacity > 0 &&
        dist[node_id] <
            dist[e.to]) { // 流せる余裕があり、かつsourceからの距離が増加する方法である場合
      int tmp_flow = dfs(e.to, sink, min(flow, e.capacity)); // 流せるだけ流す
      if (tmp_flow > 0) {                                    // 流せた場合
        e.capacity -= tmp_flow; // 流した分、エッジの容量を削減する
        G[e.to][e.rev_index].capacity +=
            tmp_flow; // 逆辺の容量を、流した分だけ増加させる
        return tmp_flow;
      }
    }
  }
  return 0;
}

// sourceからsinkへの最大流を求める
int max_flow(int source, int sink) { // source:始点 sink:終点
  int flow = 0, add;
  while (true) { // 増加パスが存在する限り、流量を追加し続ける
    bfs(source);
    if (dist[sink] < 0)
      break; // sourceからsinkへと辿り着く残余グラフがない、つまり増加パスが無くなった場合、break
    for (int i = 0; i < V; i++)
      cheked_index[i] = 0;
    while ((add = dfs(source, sink, BIG_NUM)) >
           0) { // 増加パスが見つかる間、加算
      flow += add;
    }
  }
  return flow;
}

void func() {

  MAP.clear();
  for (int i = 0; i < NUM; i++)
    G[i].clear();

  int num, tmp, index = 2;
  scanf("%d", &num);

  int source = 0, sink = 1;

  for (int loop = 0; loop < num; loop++) {
    scanf("%d", &tmp);
    MAP[tmp] = index;
    add_edge(source, index, 1); // sourceからindexに、容量1の辺を張る
    index++;
  }

  int integrate;

  for (int loop = 0; loop < N; loop++) {
    scanf("%d", &num);
    add_edge(index, sink, 1); // 1人の人物につき、最大流量1の集約路を張る
    integrate = index;
    index++;

    for (int i = 0; i < num; i++) {
      scanf("%d", &tmp);
      auto at = MAP.find(tmp);
      if (at == MAP.end())
        continue; // Isaccの都合の良い日でなければ無視
      add_edge(MAP[tmp], integrate, 1); // Isaccの都合の良い日から、
    }
  }

  V = index;

  printf("%d\\n", max_flow(source, sink));
}

int main() {

  while (true) {
    scanf("%d", &N);
    if (N == 0)
      break;

    func();
  }

  return 0;
}


Error: 0

Fixed submission:

#include <algorithm>
#include <cfloat>
#include <cmath>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <stack>
#include <stdio.h>
#include <string>
#include <time.h>
#include <vector>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;

#define NUM 3000

// 辺を表す構造体(行先、容量、逆辺のインデックス)
struct Edge {
  Edge(int arg_to, int arg_capacity, int arg_rev_index) {
    to = arg_to;
    capacity = arg_capacity;
    rev_index = arg_rev_index;
  }
  int to, capacity, rev_index;
};

int V, E;
int N;
map<int, int> MAP;
vector<Edge> G[NUM];   // グラフの隣接リスト表現
int dist[NUM];         // sourceからの距離
int cheked_index[NUM]; // どこまで調べ終わったか

// fromからtoへ向かう容量capacityの辺をグラフに追加する
void add_edge(int from, int to, int capacity) {
  G[from].push_back(Edge(to, capacity, G[to].size()));
  G[to].push_back(Edge(from, 0, G[from].size() - 1)); // 逆辺の、初期容量は0
}

// sourceからの最短距離をBFSで計算する
void bfs(int source) {
  for (int i = 0; i < V; i++)
    dist[i] = -1;
  queue<int> Q;
  dist[source] = 0;
  Q.push(source);

  while (!Q.empty()) {
    int node_id = Q.front();
    Q.pop();
    for (int i = 0; i < G[node_id].size(); i++) {
      Edge &e = G[node_id][i];
      if (e.capacity > 0 &&
          dist[e.to] < 0) { // 辺の容量が正で、かつエッジの行先に未訪問の場合
        dist[e.to] = dist[node_id] + 1;
        Q.push(e.to);
      }
    }
  }
}

// 増加パスをDFSで探す
int dfs(int node_id, int sink, int flow) {
  if (node_id == sink)
    return flow; // 終点についたらflowをreturn

  for (int &i = cheked_index[node_id]; i < G[node_id].size();
       i++) { // node_idから出ているエッジを調査
    Edge &e = G[node_id][i];
    if (e.capacity > 0 &&
        dist[node_id] <
            dist[e.to]) { // 流せる余裕があり、かつsourceからの距離が増加する方法である場合
      int tmp_flow = dfs(e.to, sink, min(flow, e.capacity)); // 流せるだけ流す
      if (tmp_flow > 0) {                                    // 流せた場合
        e.capacity -= tmp_flow; // 流した分、エッジの容量を削減する
        G[e.to][e.rev_index].capacity +=
            tmp_flow; // 逆辺の容量を、流した分だけ増加させる
        return tmp_flow;
      }
    }
  }
  return 0;
}

// sourceからsinkへの最大流を求める
int max_flow(int source, int sink) { // source:始点 sink:終点
  int flow = 0, add;
  while (true) { // 増加パスが存在する限り、流量を追加し続ける
    bfs(source);
    if (dist[sink] < 0)
      break; // sourceからsinkへと辿り着く残余グラフがない、つまり増加パスが無くなった場合、break
    for (int i = 0; i < V; i++)
      cheked_index[i] = 0;
    while ((add = dfs(source, sink, BIG_NUM)) >
           0) { // 増加パスが見つかる間、加算
      flow += add;
    }
  }
  return flow;
}

void func() {

  MAP.clear();
  for (int i = 0; i < NUM; i++)
    G[i].clear();

  int num, tmp, index = 2;
  scanf("%d", &num);

  int source = 0, sink = 1;

  for (int loop = 0; loop < num; loop++) {
    scanf("%d", &tmp);
    MAP[tmp] = index;
    add_edge(source, index, 1); // sourceからindexに、容量1の辺を張る
    index++;
  }

  int integrate;

  for (int loop = 0; loop < N; loop++) {
    scanf("%d", &num);
    add_edge(index, sink, 1); // 1人の人物につき、最大流量1の集約路を張る
    integrate = index;
    index++;

    for (int i = 0; i < num; i++) {
      scanf("%d", &tmp);
      auto at = MAP.find(tmp);
      if (at == MAP.end())
        continue; // Isaccの都合の良い日でなければ無視
      add_edge(MAP[tmp], index, 1); // Isaccの都合の良い日から、
      add_edge(index, integrate, 1);
      index++;
    }
  }

  V = index;

  printf("%d\\n", max_flow(source, sink));
}

int main() {

  while (true) {
    scanf("%d", &N);
    if (N == 0)
      break;

    func();
  }

  return 0;
}