1.题目链接。题目大意:给定一个有向图,从图中一点a到另一点b只走k步(包括b)有多少种方案?
2.这是一个很有用的性质,结论就是这个图邻接矩阵的k次幂对应的矩阵那个点的数值。其实证明也不难,我们从矩阵乘法可以看出一点端倪:c[i][j]=c[i][j]+a[i][k]*b[k][j].这个k就是位于i和j之间的点,枚举k,求和就是方案数。这个性质我忘了叫做什么了,只是在学习离散的时候听老师讲了一下,当时觉得还是比较有用的,就记了下来。代码如下:
#include<bits/stdc++.h>
#include<string>
using namespace std;
#pragma warning(disable:4996)
struct Sarray
{
static const int LEN = 25;
static const int mod = 1000;
int len, data[LEN][LEN];
Sarray(int len, int flag) :len(len) {
for (int i = 0; i < len; i++) {
for (int j = 0; j < len; j++)data[i][j] = 0;
data[i][i] = flag;
}
}
Sarray() {};
Sarray operator *(const Sarray&a) {
Sarray tem(a.len, 0);
for (int i = 0; i < len; i++) {
for (int j = 0; j < len; j++) {
for (int k = 0; k < len; k++) {
tem.data[i][j] = (tem.data[i][j] + data[i][k] * a.data[k][j]) % mod;
}
}
}
return tem;
}
Sarray operator +(const Sarray&a)
{
Sarray tem(a.len, 0);
for (int i = 0; i < len; i++) {
for (int j = 0; j < len; j++) {
tem.data[i][j] = (data[i][j] + a.data[i][j]) % mod;
}
}
return tem;
}
};
Sarray qpow(Sarray a, int b)
{
Sarray tem(a.len, 1);
while (b) {
if (b & 1)tem = a * tem;
a = a * a;
b >>= 1;
}
return tem;
}
Sarray g(25, 0);
int main()
{
int n, m;
while (~scanf("%d%d", &n, &m) && (n + m))
{
memset(g.data, 0, sizeof(g.data));
for (int i = 0; i < m; i++)
{
int u, v;
scanf("%d%d", &u, &v);
g.data[u][v] = 1;
}
int T;
scanf("%d", &T);
while (T--)
{
int a, b, k;
scanf("%d%d%d", &a, &b, &k);
Sarray c = qpow(g, k);
cout << c.data[a][b] << endl;
}
}
}
最后需要说明的是:在我们if判断的时候,千万不要写成while(~scanf("%d%d",&n,&m)&&n&&m).为什么呢,因为这里m是可以为0的,m为0的时候就是在说这个图中没有任何的边的存在,这个图也是合法的,所以这样判断输入结束是错误的。