K短路计数
- 同学出的题目,有原题的,但找不到了。
Description
- 题目背景(来源):小 L 从《挑战程序设计竞赛》中翻到了一道图论(暴力)好题。
给定一个 n 个定顶点,边长为 1 的有向图邻接矩阵。求这个图中长度为 k 的不同的路径
总数。(不懂看样例)
1.路径中同一条边可经过多次。
2.输出答案对(1e7)+7 取模。
3.图中会有自环。
Input
- 输入文件名为 count.in。
输入第一行为两个用空格隔开正整数,分别为 n 和 k 的值。
接下来输入 n 行(一个普通的邻接矩阵(不懂看样例)),
每行 n 个用空格隔开的数字(1/0),代表着从 u 到 v(有/没有)连着一条有向边。
Output
- 输出文件名为 count.out。
输出一个整数,为图中长度为 k 的路径总数。
Sample Input
3 2
0 1 0
1 0 1
1 0 0
Sample Output
5
题解:
- 矩阵乘法。
- 会了就是裸题,不会的话,还挺有思考价值的。
- 思考原图,如果将原图每个位置的值相加,答案是长度为1的的路径数,显然。
- 那么,如果长度要为2,就要在原图的基础上,枚举一次中转点。例如,有3个点。原来1 -> 2是一条路,这时我就要尝试以2为中转点,看看2到1/2/3有没有路。假设2 -> 3有两条路。那么1 -> 3就有1 * 2 = 2路。
- 仔细观察,发现以一个点为中转点进行尝试时,刚好跟矩阵乘法的运算顺序是一样的。
- 那么每枚举一个中转点等价于做一个矩阵乘法。那么答案就是(原图矩阵的k次方)所以位置元素之和了。
#include <iostream>
#include <cstdio>
#include <cstring>
#define N 105
#define hry 10000007
#define int long long
#define re register
using namespace std;
struct A
{
int m[N][N];
A() {memset(m, 0, sizeof(m));}
} a;
int n, k, ans;
inline A mul(A x, A y)
{
A z;
for(re int i =1 ; i <= n; i++)
for(re int j = 1; j <= n; j++)
for(re int k = 1; k <= n; k++)
z.m[i][j] += x.m[i][k] * y.m[k][j],
z.m[i][j] %= hry;
return z;
}
inline A power(A a, int b)
{
A r = a, base = a;
while(b)
{
if(b & 1) r = mul(r, base);
base = mul(base, base);
b >>= 1;
}
return r;
}
signed main()
{
cin >> n >> k;
for(re int i = 1; i <= n; i++)
for(re int j = 1; j <= n; j++)
cin >> a.m[i][j];
a = power(a, k - 1);
for(re int i = 1; i <= n; i++)
for(re int j = 1; j <= n; j++)
ans += a.m[i][j], ans %= hry;
cout << ans;
return 0;
}
原文地址:https://www.cnblogs.com/BigYellowDog/p/11386166.html
时间: 2024-11-08 23:35:06