POJ3613 经过K条边的最短路径 矩阵乘法 + floyd

以下选自:matrix67  十个利用矩阵乘法解决的经典问题

经典题目8 给定一个有向图,问从A点恰好走k步(允许重复经过边)到达B点的方案数modp的值
    把给定的图转为邻接矩阵,即A(i,j)=1当且仅当存在一条边i->j。令C=A*A,那么C(i,j)=ΣA(i,k)*A(k,j),实际上就等于从点i到点j恰好经过2条边的路径数(枚举k为中转点)。类似地,C*A的第i行第j列就表示从i到j经过3条边的路径数。同理,如果要求经过k步的路径数,我们只需要二分求出A^k即可。
   

    由上可得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.csdn.net/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;
}


你可能感兴趣的:(c,算法,Matrix,联想)