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

#include <cassert>
#include <climits>
#include <fstream>
#include <iostream>
#include <stdint.h>
#include <stdio.h>

#include <string>
#include <vector>
using namespace std;

#define DEBUG (0)

#if DEBUG
#define DPRINTF(...)                                                           \\
  do {                                                                         \\
    printf("D(L%d) %s: ", __LINE__, __func__);                                 \\
    printf(__VA_ARGS__);                                                       \\
  } while (false)
#else
#define DPRINTF(...)
#endif // DEBUG

enum e_state {
  UNVISITED = 0,
  CANDITATE,
  VISITED,
};

const int kInvalid = -1;
const uint8_t kMaxN = 100;
int g_numOfVertices;
int g_weightOfEdge[kMaxN][kMaxN];
int g_minWeight[kMaxN];
e_state g_visited[kMaxN];

void printAllWeights() {
  DPRINTF("Number of vertices %d\\n", g_numOfVertices);

  for (int i = 0; i < g_numOfVertices; i++) {
    for (int j = 0; j < g_numOfVertices; j++) {
      if (j == 0)
        DPRINTF("");
      printf(" %d", g_weightOfEdge[i][j]);
    }
    cout << endl;
  }
}

void printAllPath() {
  DPRINTF("Number of vertices %d\\n", g_numOfVertices);

  for (int i = 0; i < g_numOfVertices; i++) {
    for (int j = 0; j < g_numOfVertices; j++) {
      if (g_weightOfEdge[i][j] > 0)
        printf("%d -> %d (%d)\\n", i, j, g_weightOfEdge[i][j]);
    }
  }
}

bool isConnected(int a, int b) {
  if (g_weightOfEdge[a][b] == kInvalid)
    return false;
  else
    return true;
}

void updateStatus(int v) {
  g_visited[v] = VISITED;

  // mark neighthoods to CANDITATE
  for (int i = 0; i < g_numOfVertices; i++) {
    if (isConnected(v, i) && g_visited[i] == UNVISITED)
      g_visited[i] = CANDITATE;
  }

#if (1) & DEBUG
  for (int i = 0; i < g_numOfVertices; i++) {
    DPRINTF("[%d] ", i);
    switch (g_visited[i]) {
    case UNVISITED:
      cout << "UNVISITED" << endl;
      break;
    case CANDITATE:
      cout << "CANDITATE" << endl;
      break;
    case VISITED:
      cout << "VISITED" << endl;
      break;
    default:
      assert(false);
      break;
    }
  }
#endif
}

void updateMinWeight() {
  for (int i = 0; i < g_numOfVertices; i++) {
    if (g_visited[i] == VISITED) {
      for (int j = 0; j < g_numOfVertices; j++) {
        if (isConnected(i, j) && g_visited[j] == CANDITATE) {
          if (g_minWeight[j] > g_weightOfEdge[i][j]) {
            g_minWeight[j] = g_weightOfEdge[i][j];
          }
        }
      }
    }
  }

#if (1) & DEBUG
  for (int i = 0; i < g_numOfVertices; i++) {
    if (g_minWeight[i] < INT_MAX)
      DPRINTF("[%d] %d\\n", i, g_minWeight[i]);
  }
#endif
}

int takeUnvisitedVertex() {
  for (int i = 0; i < g_numOfVertices; i++)
    if (g_visited[i] == CANDITATE)
      return i;

  // make sure g_visited[i] has one CANDITATE element at least
  assert(false);
  return -1;
}

bool haveUnvisitedVertex() {
  for (int i = 0; i < g_numOfVertices; i++)
    if (g_visited[i] != VISITED)
      return true;

  return false;
}

int minSpanningTree() {
  int sumOfWeight = 0;
  const int entryPoint = 0;

  // g_visited[entryPoint] = VISITED;
  updateStatus(entryPoint);

  while (haveUnvisitedVertex()) {
    // update weight on edges that is neighborhood
    updateMinWeight();

    // take minimum edge, mark it as visited
    int minVertex, minWeight = INT_MAX;

    for (int i = 0; i < g_numOfVertices; i++) {
      if (g_visited[i] == CANDITATE && g_minWeight[i] < minWeight) {
        minVertex = i;
        minWeight = g_minWeight[i];
      }
    }

    assert(minWeight != INT_MAX);

    sumOfWeight += minWeight;
    updateStatus(minVertex);
  }

  return sumOfWeight;
}

int main() {
  cin >> g_numOfVertices;
  cin.ignore();

  DPRINTF("Number of vertices %d\\n", g_numOfVertices);

  for (int i = 0; i < g_numOfVertices; i++) {
    for (int j = 0; j < g_numOfVertices; j++)
      cin >> g_weightOfEdge[i][j];

    cin.ignore();
  }

  // init
  for (int i = 0; i < g_numOfVertices; i++) {
    g_minWeight[i] = INT_MAX;
    g_visited[i] = UNVISITED;
  }

#if DEBUG
  DPRINTF("Number of vertices %d\\n", g_numOfVertices);
  printAllWeights();
  // printAllPath();
#endif // DEBUG

  cout << minSpanningTree() << endl;

  return 0;
}


Error: TLE

Fixed submission:

#include <cassert>
#include <climits>
#include <fstream>
#include <iostream>
#include <stdint.h>
#include <stdio.h>

#include <cstring>
#include <string>
#include <vector>
using namespace std;

#define DEBUG (0)

#if DEBUG
#define DPRINTF(...)                                                           \\
  do {                                                                         \\
    printf("D(L%d) %s: ", __LINE__, __func__);                                 \\
    printf(__VA_ARGS__);                                                       \\
  } while (false)
#else
#define DPRINTF(...)
#endif // DEBUG

const int kMaxN = 100;
const int kInvalid = INT_MAX;
int g_weightOfVij[kMaxN][kMaxN];
int g_numOfVertices;

struct Edge {
  Edge(int v0, int v1) : v0_(v0), v1_(v1) {}

  int v0_;
  int v1_;
  int getWeight() { return g_weightOfVij[v0_][v1_]; }
};

struct VisitData {
  VisitData(int num) : numOfData_(num), totalWeight_(0) {
    memset(visited_, 0, kMaxN);
  }

  bool visited_[kMaxN];
  int numOfData_;
  int totalWeight_;

  bool isAllVisited();

#if DEBUG
  vector<int> path_; // for history of pathes
#endif               // DEBUG
};

bool VisitData::isAllVisited() {
  for (int i = 0; i < numOfData_; i++)
    if (visited_[i] == false)
      return false;

  return true;
}

void printAllWeights() {
  DPRINTF("Number of vertices %d\\n", g_numOfVertices);

  for (int i = 0; i < g_numOfVertices; i++) {
    for (int j = 0; j < g_numOfVertices; j++) {
      if (j == 0)
        DPRINTF("");
      printf(" %d", g_weightOfVij[i][j]);
    }
    cout << endl;
  }
}

void printAllPath() {
  DPRINTF("Number of vertices %d\\n", g_numOfVertices);
  DPRINTF("$src -> $dst ($weight)\\n");

  for (int i = 0; i < g_numOfVertices; i++) {
    for (int j = 0; j < g_numOfVertices; j++) {
      if (g_weightOfVij[i][j] > 0)
        DPRINTF("%d -> %d (%d)\\n", i, j, g_weightOfVij[i][j]);
    }
  }
}

void getConnectedVertices(int pos, vector<int> &vertices) {
  for (int i = 0; i < g_numOfVertices; i++)
    if (g_weightOfVij[pos][i] > 0)
      vertices.push_back(i);

#if 0
  DPRINTF("connected points from %d :", pos);
  for (int i = 0; i < vertices.size(); i++)
    printf(" %d", vertices[i]);

  cout << endl;
#endif
}

/* find unvisited vertices that are connected from the vertices already visited
 */
void getNextCandidates(const bool visited[kMaxN], vector<Edge> &candidates) {
#if 0
  DPRINTF("visited:\\n");
  for (int i = 0; i < g_numOfVertices; i++)
    DPRINTF("  [%d] = %d\\n", i, visited[i]);
#endif

  for (int startV = 0; startV < g_numOfVertices; startV++) {
    if (visited[startV] == true) {
      // Get all connected vertices
      vector<int> vertices;
      getConnectedVertices(startV, vertices);

      // Remove vertices that are already visited
      for (int nextV : vertices) {
        if (visited[nextV] == false)
          candidates.push_back(Edge(startV, nextV));
      }
    }
  }

#if 0
  DPRINTF("Next candidates:\\n");
  for (int i = 0; i < candidates.size(); i++)
    printf("  %d -> %d\\n", candidates[i].v0_, candidates[i].v1_);
#endif
}

// int findSpanningTree(int vertex, VisitData info /* Not pointer nor reference
// */)
int findSpanningTree(int vertex, VisitData &info) {

  assert(info.visited_[vertex] == false);
  info.visited_[vertex] = true;

#if DEBUG
  info.path_.push_back(vertex);
#endif

#if 1 & DEBUG
  DPRINTF("Path:");
  for (int i = 0; i < info.path_.size(); i++)
    printf(" %d", info.path_[i]);
  cout << endl;
#endif

  if (info.isAllVisited()) {
    DPRINTF("all vertices visited. total weight %d\\n", info.totalWeight_);
    return info.totalWeight_;
  }

  vector<Edge> nextPosCandidates;
  getNextCandidates(info.visited_, nextPosCandidates);

  int minWeight = kInvalid;

  for (int i = 0; i < nextPosCandidates.size(); i++) {
    const int startV = nextPosCandidates[i].v0_;
    const int nextV = nextPosCandidates[i].v1_;

    VisitData nextInfo = info;
    nextInfo.totalWeight_ += g_weightOfVij[startV][nextV];

    const int weight = findSpanningTree(nextV, nextInfo);

    if (weight != kInvalid && weight < minWeight)
      minWeight = weight;
  }

  DPRINTF("minWeight %d\\n", minWeight);
#if 1 & DEBUG
  DPRINTF("  Path:");
  for (int i = 0; i < info.path_.size(); i++)
    printf(" %d", info.path_[i]);
  cout << endl;
#endif

  return minWeight;
}

int main() {
  cin >> g_numOfVertices;
  cin.ignore();

  DPRINTF("Number of vertices %d\\n", g_numOfVertices);

  for (int i = 0; i < g_numOfVertices; i++) {
    for (int j = 0; j < g_numOfVertices; j++)
      cin >> g_weightOfVij[i][j];

    cin.ignore();
  }

#if DEBUG
  DPRINTF("Number of vertices %d\\n", g_numOfVertices);
  printAllWeights();
  // printAllPath();
#endif // DEBUG

  const int startPos = 0;
  VisitData info(g_numOfVertices);

  cout << findSpanningTree(startPos, info) << endl;

  return 0;
}