以下选自:matrix67 十个利用矩阵乘法解决的经典问题
经典题目8 给定一个有向图,问从A点恰好走k步(允许重复经过边)到达B点的方案数modp的值
由上可得ans = A^ A ans[i][j]是从i到j经过两条边枚举所有情况可得,联想到floyd算法类似矩阵乘法的形式,可以将矩阵乘法的部分改为松驰边的操作,便解决这问题
这里本来用递归实现矩阵乘法,结果栈爆了,只好用循环模拟递归。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <stack>
using namespace std;
struct MATRIX
{
int m[250][250];
};
MATRIX mul(MATRIX num1, MATRIX num2, int n)
{
int i,j,k;
MATRIX res;
memset(&res, 63, sizeof(res));
for(k = 1; k <= n; k++)//这行调到最外循环也可以
for(i = 1; i <= n; i++)
{
for(j = 1; j <= n; j++)
{
{
if(num1.m[i][k] + num2.m[k][j] < res.m[i][j])
{
res.m[i][j] = num1.m[i][k] + num2.m[k][j];
}
}
}
}
return res;
}
MATRIX POW(MATRIX map,int n,int k)
{
/* MATRIX first;
memcpy(&first, &map, sizeof(map));
if(k ==1)
{
return map;
}
MATRIX res;
int sta[50];
int cnt = 0;
while(k)
{
if(k % 2 == 1)
{
//sta.push(1);
sta[cnt++] = 1;
}
else
{
//sta.push(0);
sta[cnt++] = 0;
}
k = (k >> 1);
}//为方便模拟递归 http://blog.youkuaiyun.com/paul08colin/article/details/7411506
cnt--;//去掉第一个栈顶元素
while(cnt != 0)
{
if(sta[--cnt]== 0)
{
res = mul(map,map,n);
memcpy(&map,&res,sizeof(res));
}
else
{
res = mul(map,map,n);
res = mul(res,first,n);
memcpy(&map,&res,sizeof(res));
}
}*/
//////上面注释部分是方法1,模拟递归。效率会相对低些
MATRIX res;
int i;
bool flag = true;
while(k)
{
if( k & 1)
{
if(flag == true)
{
memcpy(&res,&map,sizeof(map));
flag = false;
}
else
{
res = mul(res,map,n);
}
}
map = mul(map,map,n);
k>>=1;
}
// return res;
return res;
///上面是用二进制的思想,效率较快
}
int main()
{
int k,n,s,t;
while(scanf("%d %d %d %d", &k, &n, &s, &t) != EOF)
{
int i;
int f[1010];
memset(f,0,sizeof(f));
MATRIX map;
memset(&map,63,sizeof(map));
//printf("%d\n",map.m[0][0]);
int from,to,len;
int MAX = 1;
for(i = 0; i < n; i++)
{
scanf("%d %d %d",&len, &from, &to);
if(f[from] == 0)
{
f[from] = MAX++;
}
if(f[to] == 0)
{
f[to] = MAX++;
}
map.m[f[from]][f[to] ] = len;
map.m[f[to]][f[from]] = len;
}
MAX--;
MATRIX res;
res = POW(map,MAX,k);
printf("%d\n",res.m[f[s]][f[t]]);
}
return 0;
}