您的位置:首页 > 其它

bzoj1297 [SCOI2009]迷路

2017-09-18 21:23 405 查看

1297: [SCOI2009]迷路

Time Limit: 10 Sec Memory Limit: 162 MB
Submit: 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

Sample Output

【输出样例一】

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]
);

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: