poj3613 Cow Relays(最短路/矩阵快速幂+floyd/经过k条边的APSP)

题目

t(t<=100)条边,每个边两端的点的编号在1-1e3之间

边权w<=1e3

给一个起点S,一个终点E,

求S->E经过n<=1e6条边的最短路

思路来源

https://blog.****.net/monster__yi/article/details/51069236

马老师!!!

题解

我今天要吹爆mls!!!

poj3613 Cow Relays(最短路/矩阵快速幂+floyd/经过k条边的APSP)

本来wa得不能自已,马老师一点就AC了

不能加自己到自己的0的边,

即不能令A[i][i]=0

如以下样例:

Input:
3 1 1 2
3 1 2
Output:
9

矩阵A[i][j]代表i->j的经过1条边的最短路,

poj3613 Cow Relays(最短路/矩阵快速幂+floyd/经过k条边的APSP)则为代表i->j的经过k条边的最短路,

矩阵乘法的过程,行*列的时候,

相当于加一个点,即枚举加一条边构成新的最短路

Trick

快速幂里面,要把B先赋成A这个矩阵,然后倍增少一次即可

因为对于A这种矩阵,

既不能把零次单位矩阵B全赋成INF,也不能全赋0,

也不能主对角线赋0,其余地方赋INF

所以就赋A之后,少搞一次就可以了,

B的倍增和A的倍增是一样的

代码

#include <iostream>
#include <algorithm> 
#include <cstring>
#include <cstdio>
#include <vector>
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
typedef vector<int> vec;
typedef vector<vec> mat;
struct edge
{
	int u,v,w;
}e[205];
int id[1005],cnt,a[2005];
mat mul(mat &A, mat &B){
    mat C(A.size(), vec(B[0].size()));
    for(int i=0;i<C.size();++i)
	{
		for(int j=0;j<C[0].size();++j)
		{
		  C[i][j]=INF;
	    }   
	}
    for(int i = 0; i < A.size(); i++)
	{
        for(int j = 0; j < B[0].size(); j++)
		{
			for(int k = 0; k < B.size(); k++)
		    {
			   C[i][j]=min(C[i][j],A[i][k]+B[k][j]);
            }
        }
    }
    return C;
}
 
mat modpow(mat A, ll n){
    mat B(A.size(), vec(A.size()));
    B=A;n--;
    while(n)
	{
        if(n & 1) B = mul(B, A);
        A = mul(A, A);
        n >>= 1; 
    }
    return B;
}
int n,t,S,E;
int main()
{
	while(~scanf("%d%d%d%d",&n,&t,&S,&E))
	{
		cnt=0;
		memset(id,0,sizeof(id));
		for(int i=0;i<t;++i)
		{
			scanf("%d%d%d",&e[i].w,&e[i].u,&e[i].v);
		    a[cnt++]=e[i].u;
			a[cnt++]=e[i].v; 
		} 
		sort(a,a+cnt);
		int num=unique(a,a+cnt)-a;
		for(int i=0;i<num;++i)id[a[i]]=i;
		mat A(num, vec(num));
		for(int i=0;i<num;++i)
		{
			for(int j=0;j<num;++j)
			{
			  A[i][j]=INF;
		    }
		}
		for(int i=0;i<t;++i)
		{
			A[id[e[i].u]][id[e[i].v]]=min(A[id[e[i].u]][id[e[i].v]],e[i].w);
			A[id[e[i].v]][id[e[i].u]]=min(A[id[e[i].v]][id[e[i].u]],e[i].w);
			//printf("A[%d][%d]:%d\n",id[e[i].u],id[e[i].v],e[i].w);
		}
		/*for(int i=0;i<num;++i)
		{
			for(int j=0;j<num;++j)
			printf("A[%d][%d]:%d\n",i,j,A[i][j]);
		}*/
        A = modpow(A, n);
        printf("%d\n",A[id[S]][id[E]]); 
    }
    return 0; 
}