LGV 引理
简介
Lindström–Gessel–Viennot lemma,即 LGV 引理,可以用来处理有向无环图上不相交路径计数等问题。
前置知识:图论相关概念 中的基础部分、矩阵、高斯消元求行列式。
LGV 引理仅适用于 有向无环图。
定义
起点集合 
终点集合 
一组 
引理
其中 
证明
由行列式定义可得
观察到 
此处 
设 
设 
因此我们有 
则 
证毕1。
例题
例 1 CF348D Turtles
题意:有一个 
比较直接的 LGV 引理的应用。考虑所有合法路径,发现从 
其中 
参考代码
#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;
}
例 2 HDU 5852 Intersection is not allowed!
题意:有一个 
观察到如果路径不相交就一定是 
从 
行列式可以使用高斯消元求。
复杂度为 
参考代码
#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;
}
参考资料
-  
证明来源于 知乎 - LGV 引理证明 ↩
 
创建日期: 2019年9月1日