1297: [SCOI2009]迷路
Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 1366 Solved: 976
[Submit][Status][Discuss]
Description
windy在有向图中迷路了。 该有向图有 N 个节点,windy从节点 0 出发,他必须恰好在 T 时刻到达节点 N-1。 现在给出该有向图,你能告诉windy总共有多少种不同的路径吗? 注意:windy不能在某个节点逗留,且通过某有向边的时间严格为给定的时间。
Input
第一行包含两个整数,N T。 接下来有 N 行,每行一个长度为 N 的字符串。 第i行第j列为'0'表示从节点i到节点j没有边。 为'1'到'9'表示从节点i到节点j需要耗费的时间。
Output
包含一个整数,可能的路径数,这个数可能很大,只需输出这个数除以2009的余数。
Sample Input
【输入样例一】
2 2
11
00
【输入样例二】
5 30
12045
07105
47805
12024
12345
2 2
11
00
【输入样例二】
5 30
12045
07105
47805
12024
12345
Sample Output
【输出样例一】
1
【样例解释一】
0->0->1
【输出样例二】
852
1
【样例解释一】
0->0->1
【输出样例二】
852
HINT
30%的数据,满足 2 <= N <= 5 ; 1 <= T <= 30 。 100%的数据,满足 2 <= N <= 10 ; 1 <= T <= 1000000000 。
分析:有一道比较经典的题,求恰好经过k条边的最短路,这道题可以用矩阵乘法来做,这道题和那道题是类似的,不过边权有变化,那怎么办呢?拆点就好了,因为边权最多为9,所以每个点拆成9个点,上一个点向下一个点连边权为1的边,点与点之间连边的话,边权为几,就连向拆成的第几个点,最后矩阵快速幂就解决了.
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; const int mod = 2009; int n, t, maxn,b[200][200],ans[200][200],temp[200][200]; int c(int x, int y) { return (y - 1) * n + x; } void mul1() { memset(temp, 0, sizeof(temp)); for (int i = 1; i <= maxn; i++) for (int j = 1; j <= maxn; j++) for (int k = 1; k <= maxn; k++) { temp[i][j] += ans[i][k] * b[k][j]; temp[i][j] %= mod; } memcpy(ans, temp, sizeof(ans)); } void mul2() { memset(temp, 0, sizeof(temp)); for (int i = 1; i <= maxn; i++) for (int j = 1; j <= maxn; j++) for (int k = 1; k <= maxn; k++) { temp[i][j] += b[i][k] * b[k][j]; temp[i][j] %= mod; } memcpy(b, temp, sizeof(b)); } void qpow(int b) { while (b) { if (b & 1) mul1(); b >>= 1; mul2(); } } int main() { scanf("%d%d", &n, &t); for (int i = 1; i <= n; i++) for (int j = 2; j <= 9; j++) b[c(i, j)][c(i, j - 1)] = 1; for (int i = 1; i <= n; i++) { for (int j = 1; j <= n; j++) { int x; scanf("%1d", &x); if (!x) continue; b[i][c(j, x)] = 1; } } maxn = n * 9; for (int i = 1; i <= maxn; i++) ans[i][i] = 1; qpow(t); printf("%d\n", ans[1][n]); return 0; }