有向图
给你一个 \(n+m\) 的有向图,边上带 \(\in (0,1]\) 的边权。
保证:
- \(\forall x,y \in [1,n]\),\(x\) 与 \(y\) 之间存在一对反向边。
- \(\forall x\in [1,n],y\in[n+1,n+m]\),存在一条从 \(x\) 到 \(y\) 的单向边。
- \(\forall x,y\in [n+1,n+m]\),\(x\) 与 \(y\) 之间没有任何边。
从时刻 \(0\) 开始,若当前在 \(x\),下一个时刻走到 \(y\) 的概率是 \(x\) 指向 \(y\) 的边的边权。保证一个点的出边边权之和为 \(1\)。
从点 \(1\) 开始游走,求无穷多步之后停在每个点的概率。
设 \(x_i\) 表示所有以 \(i\) 为结尾的路径出现的概率之和。
那么不难有以下转移:
\[x_i=\sum_j p_{j,i} x_j
\]
显然概率之和为 \(1\),所以还有额外的一条:
\[\sum_i x_i=1
\]
但是这种情况下整个方程组不一定有解,怎么办呢。
我们可以将后 \(m\) 个点全部向 \(1\) 连边权为 \(1\) 的单向边。
这相当于我们经过了一次后 \(m\) 个点之一后重新开始一轮。
不难发现这样不影响最后的答案。
同时我们会发现,这种情况下,所有点的出边边权之和都为 \(1\)。
那么图的邻接矩阵 \(G\) 就是一个行随机矩阵,\(1\) 必然是 \(G\) 的特征值。
所以如果我们考虑这个等价的方程:
\[G\textbf x=\textbf x
\]
因此必然存在解。
解出来后,将后 \(m\) 个点的答案归一化后输出即可。
#include <algorithm>
#include <iostream>
#include <vector>
const int O = 1e9 + 7, N = 501;
typedef long long i64;
i64 O_inv(i64 a, int O = O) {
i64 res = 1, base = a, power = O - 2;
while (power) {
if (power & 1) res = res * base % O;
base = base * base % O;
power >>= 1;
}
return res;
}
const i64 i4 = O_inv(10000);
std::vector<i64> solveLinearSystem(std::vector<std::vector<i64>> A, std::vector<i64> B) {
int n = A.size(), m = A[0].size();
std::vector<std::vector<i64>> aug(n, std::vector<i64>(m + 1));
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++)
aug[i][j] = A[i][j];
aug[i][m] = B[i];
}
std::vector<int> where(m, -1);
int row = 0;
for (int col = 0; col < m && row < n; col++) {
int pivot = -1;
for (int i = row; i < n; i++) {
if (aug[i][col] != 0) {
pivot = i;
break;
}
}
std::swap(aug[row], aug[pivot]);
where[col] = row;
int inv = O_inv(aug[row][col], O);
for (int j = col; j <= m; j++) {
aug[row][j] = (1LL * aug[row][j] * inv) % O;
}
for (int i = 0; i < n; i++) {
if (i != row && aug[i][col]) {
int factor = aug[i][col];
for (int j = col; j <= m; j++)
aug[i][j] = (aug[i][j] + O - 1LL * factor * aug[row][j] %O) % O;
}
}
row++;
}
std::vector<i64> x(m, 0);
for (int j = 0; j < m; j++) {
if (where[j] != -1) {
x[j] = aug[where[j]][m];
}
}
return x;
}
int n, m;
i64 p[N][N];
inline void solve() {
for(int i = 0; i < n; ++i)
for(int j = 0; j < n+m; ++j)
std::cin >> p[i][j], p[i][j] = p[i][j] * i4 %O;
std::vector<i64> b(n+m, 0);
std::vector<std::vector<i64>> a(n+m+1, b);
for(int j = n; j < n+m; ++j)
a[0][j] = 1;
for(int i = 0; i < n+m; ++i) {
for(int j = 0; j < n; ++j)
a[i][j] = p[j][i];
a[i][i] -= 1;
}
for(int i = 0; i < n+m; ++i)
a[n+m][i] = 1;
b.push_back(1);
auto res = solveLinearSystem(a, b);
i64 sum = 0;
for(int i = n; i < n+m; ++i)
sum += (res[i] %= O);
sum %= O, sum = O_inv(sum);
for(int i = n; i < n+m; ++i)
std::cout << res[i] * sum %O << " ";
std::cout << "\n";
}
int main() {
while(std::cin >> n >> m) {
solve();
}
}
本文来自博客园,作者:CuteNess,转载请注明原文链接:https://www.cnblogs.com/CuteNess/p/19094899

浙公网安备 33010602011771号