The LGV Lemma

Introduction

The Lindström–Gessel–Viennot lemma, or LGV lemma, can be used for problems such as counting vertex-disjoint paths in directed acyclic graphs.

Prerequisites: the basic material in Graph-theoretic concepts, Matrices, and Gaussian Elimination for Determinants.

The LGV lemma applies only to directed acyclic graphs.

Definition

ω(P)\omega(P) denotes the product of the edge weights along path PP. (For path counting, all edge weights can be set to 11.) (In fact, edge weights may be generating functions.)

e(u,v)e(u, v) denotes the sum of uu over every path vv from PP to ω(P)\omega(P), that is, e(u,v)=∑P:u→vω(P)e(u, v)=\sum\limits_{P:u\rightarrow v}\omega(P).

The source set AA is a subset of the vertex set of the directed acyclic graph, with size nn.

The target set BB is also a subset of the vertex set of the directed acyclic graph, also with size nn.

A vertex-disjoint path family A→BA\rightarrow B from SS: SiS_i is a path from AiA_i to Bσ(S)iB_{\sigma(S)_i}, where σ(S)\sigma(S) is a permutation; for any i≠ji\ne j, SiS_i and SjS_j have no common vertex.

t(σ)t(\sigma) denotes the number of inversions in permutation σ\sigma.

Lemma

M=[e(A1,B1)e(A1,B2)⋯e(A1,Bn)e(A2,B1)e(A2,B2)⋯e(A2,Bn)⋮⋮⋱⋮e(An,B1)e(An,B2)⋯e(An,Bn)]M = \begin{bmatrix}e(A_1,B_1)&e(A_1,B_2)&\cdots&e(A_1,B_n)\\ e(A_2,B_1)&e(A_2,B_2)&\cdots&e(A_2,B_n)\\ \vdots&\vdots&\ddots&\vdots\\ e(A_n,B_1)&e(A_n,B_2)&\cdots&e(A_n,B_n)\end{bmatrix} det⁡(M)=∑S:A→B(−1)t(σ(S))∏i=1nω(Si)\det(M)=\sum\limits_{S:A\rightarrow B}(-1)^{t(\sigma(S))}\prod\limits_{i=1}^n \omega(S_i)

Here, ∑S:A→B\sum\limits_{S:A\rightarrow B} denotes the sum over every vertex-disjoint A→BA\rightarrow B path family SS satisfying the requirements above.

Proof

By the definition of a determinant,

det⁡(M)=∑σ(−1)t(σ)∏i=1ne(ai,bσ(i))=∑σ(−1)t(σ)∏i=1n∑P:ai→bσ(i)ω(P)\begin{align} \det(M)&=\sum_{\sigma}(-1)^{t(\sigma)}\prod_{i=1}^n e(a_i,b_{\sigma(i)})\\ &=\sum_{\sigma}(-1)^{t(\sigma)}\prod_{i=1}^n \sum_{P:a_i\to b_{\sigma(i)}} \omega(P) \end{align}

Observe that ∏i=1n∑P:ai→bσ(i)ω(P)\prod\limits_{i=1}^n \sum\limits_{P:a_i\to b_{\sigma(i)}} \omega(P) is exactly the sum of AA over all path families BB from σ\sigma to PP whose permutation is ω(P)\omega(P).

∑σ(−1)t(σ)∏i=1n∑P:ai→bσ(i)ω(P)=∑σ(−1)t(σ)∑P=σω(P)=∑P:A→B(−1)t(σ)∏i=1nω(Pi)\begin{align} &\sum_{\sigma}(-1)^{t(\sigma)}\prod_{i=1}^n \sum_{P:a_i\to b_{\sigma(i)}} \omega(P)\\ =&\sum_{\sigma}(-1)^{t(\sigma)}\sum_{P=\sigma}\omega(P)\\ =&\sum_{P:A\to B}(-1)^{t(\sigma)}\prod_{i=1}^n \omega(P_i) \end{align}

Here, PP is an arbitrary path family.

Let UU be a vertex-disjoint path family and VV an intersecting path family.

∑P:A→B(−1)t(σ)∏i=1nω(Pi)=∑U:A→B(−1)t(U)∏i=1nω(Ui)+∑V:A→B(−1)t(V)∏i=1nω(Vi)\begin{align} &\sum_{P:A\to B}(-1)^{t(\sigma)}\prod_{i=1}^n \omega(P_i)\\ =&\sum_{U:A\to B}(-1)^{t(U)}\prod_{i=1}^n \omega(U_i)+\sum_{V:A\to B}(-1)^{t(V)}\prod_{i=1}^n \omega(V_i) \end{align}

Suppose PP contains an intersecting pair Pi:a1→u→b1,Pj:a2→u→b2P_i:a_1 \to u \to b_1,P_j:a_2 \to u \to b_2. There is necessarily a corresponding intersecting pair Pi′=a1→u→b2,Pj′=a2→u→b1P_i'=a_1\to u\to b_2,P_j'=a_2\to u\to b_1; all other paths in P′P' are the same as in PP. Therefore ω(P)=ω(P′),t(P)=t(P′)±1\omega(P)=\omega(P'),t(P)=t(P')\pm 1.

Thus ∑V:A→B(−1)t(σ)∏i=1nω(Vi)=0\sum\limits_{V:A\to B}(-1)^{t(\sigma)}\prod\limits_{i=1}^n \omega(V_i)=0.

Consequently, det⁡(M)=∑U:A→B(−1)t(U)∏i=1nω(Ui)\det(M)=\sum\limits_{U:A\to B}(-1)^{t(U)}\prod\limits_{i=1}^n \omega(U_i).

This proves the lemma.1

Examples

Example 1: CF348D Turtles

Problem statement: An n×mn\times m grid contains passable and impassable cells. A turtle at (x,y)(x, y) may move only to (x+1,y)(x+1, y) or (x,y+1)(x, y+1). Find the number of vertex-disjoint paths from (1,1)(1, 1) to (n,m)(n, m) modulo 109+710^9+7. 2≤n,m≤30002\le n,m\le3000.

This is a direct application of the LGV lemma. Consider all valid paths. Every path from (1,1)(1,1) must pass through A={(1,2),(2,1)}A=\{(1,2), (2,1)\}, and every path reaching the destination must pass through B={(n−1,m),(n,m−1)}B=\{(n-1, m), (n, m-1)\}. Thus A,BA, B can be selected immediately. Applying the LGV lemma gives:

∣f(a1,b1)f(a1,b2)f(a2,b1)f(a2,b2)∣=f(a1,b1)×f(a2,b2)−f(a1,b2)×f(a2,b1)\begin{vmatrix} f(a_1, b_1) & f(a_1, b_2) \\ f(a_2, b_1) & f(a_2, b_2) \end{vmatrix} = f(a_1, b_1)\times f(a_2, b_2) - f(a_1, b_2)\times f(a_2, b_1)

Here, f(a,b)f(a, b) is the number of paths from a→ba\rightarrow b in the graph. The path-counting problem with blocked cells can be solved by an O(nm)O(nm) DP, so ff is easy to obtain. The final complexity is O(nm)O(nm).

Reference implementation
#include <cstring>
#include <iostream>
#include <string>

using namespace std;

using ll = long long;
constexpr int MOD = 1e9 + 7;
constexpr int SIZE = 3010;

string board[SIZE];
int dp[SIZE][SIZE];

int f(int x1, int y1, int x2, int y2) {
  memset(dp, 0, sizeof dp);

  dp[x1][y1] = board[x1][y1] == '.';
  for (int i = 1; i <= x2; i++) {
    for (int j = 1; j <= y2; j++) {
      if (board[i][j] == '#') {
        continue;
      }
      dp[i][j] = (dp[i][j] + dp[i - 1][j]) % MOD;
      dp[i][j] = (dp[i][j] + dp[i][j - 1]) % MOD;
    }
  }
  return dp[x2][y2] % MOD;
}

int main() {
  ios::sync_with_stdio(false);
  cin.tie(nullptr);

  int n, m;
  cin >> n >> m;

  for (int i = 1; i <= n; i++) {
    cin >> board[i];
    board[i] = " " + board[i];
  }

  ll f11 = f(1, 2, n - 1, m);
  ll f12 = f(1, 2, n, m - 1);
  ll f21 = f(2, 1, n - 1, m);
  ll f22 = f(2, 1, n, m - 1);

  ll ans = ((f11 * f22) % MOD - (f12 * f21) % MOD + MOD) % MOD;
  cout << ans << '\n';

  return 0;
}
Example 2: HDU 5852 Intersection is not allowed!

Problem statement: An n×nn\times n board allows a piece at (x,y)(x, y) to move only to (x,y+1)(x, y+1) or (x+1,y)(x + 1, y). There are kk pieces; piece ii starts at (1,ai)(1, a_i) and must end at (n,bi)(n, b_i). The paths must be pairwise disjoint. Find the number of solutions modulo 109+710^9+7. 1≤n≤1051\le n\le 10^5, 1≤k≤1001\le k\le 100, and 1≤a1<a2<⋯<an≤n1\le a_1<a_2<\dots<a_n\le n, 1≤b1<b2<⋯<bn≤n1\le b_1<b_2<\dots<b_n\le n.

If the paths are disjoint, they must connect aia_i to bib_i, so in the LGV lemma we necessarily have σ(S)i=i\sigma(S)_i=i and need not consider signs. Set every edge weight to 11 and apply the lemma directly.

The number of paths from (1,ai)(1, a_i) to (n,bj)(n, b_j) is the number of ways to choose n−1+bj−ain-1+b_j-a_i downward steps from n−1n-1 steps, so e(Ai,Bj)=(n−1+bj−ain−1)e(A_i, B_j)=\binom{n-1+b_j-a_i}{n-1}.

The determinant can be computed with Gaussian elimination.

The complexity is O(n+k(k2+log⁡p))O(n+k(k^2 + \log p)), where log⁡p\log p is the complexity of computing a modular inverse.

Reference implementation
#include <algorithm>
#include <iostream>

using ll = long long;

constexpr int K = 105;
constexpr int N = 100005;
constexpr int mod = 1e9 + 7;

int T, n, k, a[K], b[K], fact[N << 1], m[K][K];

int qpow(int x, int y) {
  int out = 1;
  while (y) {
    if (y & 1) out = (ll)out * x % mod;
    x = (ll)x * x % mod;
    y >>= 1;
  }
  return out;
}

int c(int x, int y) {
  return (ll)fact[x] * qpow(fact[y], mod - 2) % mod *
         qpow(fact[x - y], mod - 2) % mod;
}

using std::cin;
using std::cout;

int main() {
  cin.tie(nullptr)->sync_with_stdio(false);
  fact[0] = 1;
  for (int i = 1; i < N * 2; ++i) fact[i] = (ll)fact[i - 1] * i % mod;

  cin >> T;

  while (T--) {
    cin >> n >> k;

    for (int i = 1; i <= k; ++i) cin >> a[i];
    for (int i = 1; i <= k; ++i) cin >> b[i];

    for (int i = 1; i <= k; ++i) {
      for (int j = 1; j <= k; ++j) {
        if (a[i] <= b[j])
          m[i][j] = c(b[j] - a[i] + n - 1, n - 1);
        else
          m[i][j] = 0;
      }
    }

    for (int i = 1; i < k; ++i) {
      if (!m[i][i]) {
        for (int j = i + 1; j <= k; ++j) {
          if (m[j][i]) {
            std::swap(m[i], m[j]);
            break;
          }
        }
      }
      if (!m[i][i]) continue;
      int inv = qpow(m[i][i], mod - 2);
      for (int j = i + 1; j <= k; ++j) {
        if (!m[j][i]) continue;
        int mul = (ll)m[j][i] * inv % mod;
        for (int p = i; p <= k; ++p) {
          m[j][p] = (m[j][p] - (ll)m[i][p] * mul % mod + mod) % mod;
        }
      }
    }

    int ans = 1;

    for (int i = 1; i <= k; ++i) ans = (ll)ans * m[i][i] % mod;

    cout << ans << '\n';
  }

  return 0;
}

References

Footnotes

  1. The proof is from Zhihu - Proof of the LGV Lemma ↩

This content comes from OI Wiki: The LGV Lemma. 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.