Node Splitting

Node splitting is a graph-modeling technique commonly used in network flow to handle vertex weights or vertex capacity constraints, and also frequently used in layered graphs.

Maximum flow with vertex capacity constraints

If vertices are converted into edges, the standard solution can be applied directly.

Consider converting a capacity-constrained vertex into the following structure: two vertices u,vu,v and an edge ⟨u,v⟩\left\langle u,v \right\rangle. Vertex uu receives all edges that arrive at the corresponding vertex from other vertices in the original graph, while vertex vv emits all edges that leave the corresponding original vertex toward other vertices. Set the capacity of edge ⟨u,v⟩\left\langle u,v \right\rangle to the capacity of the original vertex, and then apply the standard method. This is the basic idea of node splitting.

If the original graph is:

Figure: node

After node splitting, the graph becomes:

Figure: node split

Shortest paths in layered graphs

Consider a layered-graph shortest-path problem in which one may traverse a path at zero cost kk times and wants the minimum total cost. We can use a DP-style formulation: let disi,j\text{dis}_{i, j} denote the shortest path from the starting vertex to vertex ii after using the free-passage privilege jj times. Clearly, the dis\text{dis} array can be transitioned as follows:

disi,j=min⁡{min⁡{disfrom,j−1},min⁡{disfrom,j+w}}\text{dis}_{i, j} = \min\{\min\{\text{dis}_{from, j - 1}\}, \min\{\text{dis}_{from,j} + w\}\}

Here, fromfrom denotes the parent of ii, and ww denotes the weight of the edge just traversed. When j−1≥kj - 1 \geq k, disfrom,j\text{dis}_{from, j}=∞\infty.

In fact, this DP is equivalent to splitting every vertex into k+1k+1 vertices, with each new vertex representing arrival at the original vertex after using a different number of free passages. In other words, vertex uiu_i represents reaching vertex ii after using the free-passage privilege uu times.

「JLOI2011」Flight Routes

Problem statement: Given an undirected graph with nn vertices and mm edges, you may traverse kk roads at zero cost. Find the minimum cost from ss to tt.

Core code:

struct State {    // node structure for the priority queue
  int v, w, cnt;  // cnt is the number of free-passage privileges already used

  State() {}

  State(int v, int w, int cnt) : v(v), w(w), cnt(cnt) {}

  bool operator<(const State &rhs) const { return w > rhs.w; }
};

void dijkstra() {
  memset(dis, 0x3f, sizeof dis);
  dis[s][0] = 0;
  pq.push(State(s, 0, 0));  // reaching the start requires no free passage and has distance zero
  while (!pq.empty()) {
    const State top = pq.top();
    pq.pop();
    int u = top.v, nowCnt = top.cnt;
    if (done[u][nowCnt]) continue;
    done[u][nowCnt] = true;
    for (int i = head[u]; i; i = edge[i].next) {
      int v = edge[i].v, w = edge[i].w;
      if (nowCnt < k && dis[v][nowCnt + 1] > dis[u][nowCnt]) {  // can pass for free
        dis[v][nowCnt + 1] = dis[u][nowCnt];
        pq.push(State(v, dis[v][nowCnt + 1], nowCnt + 1));
      }
      if (dis[v][nowCnt] > dis[u][nowCnt] + w) {  // cannot pass for free
        dis[v][nowCnt] = dis[u][nowCnt] + w;
        pq.push(State(v, dis[v][nowCnt], nowCnt));
      }
    }
  }
}

int main() {
  n = read(), m = read(), k = read();
  // The code normally numbers vertices from 1 to n, but this problem uses 0 to n - 1, so adjust the indices.
  s = read() + 1, t = read() + 1;
  while (m--) {
    int u = read() + 1, v = read() + 1, w = read();
    add(u, v, w), add(v, u, w);  // this problem has undirected edges
  }
  dijkstra();
  int ans = std::numeric_limits<int>::max();  // initialize ans to the maximum int value
  for (int i = 0; i <= k; ++i)
    ans = std::min(ans, dis[t][i]);  // take the best value over all ways to reach the destination
  println(ans);
}

This content comes from OI Wiki: Node Splitting. See the original for authors and revision history. AIOJ has adapted the formatting, in-site links, and resource paths.

Content is shared under CC BY-SA 4.0 and SATA license; additional terms are governed by the original notice. Thanks to the OI Wiki authors and contributors; per the SATA terms, please visit the OI Wiki repository and star it to show your support.