题目大意:
Input
- Line 1: Four space-separated integers: N, T, S, and E
- Lines 2..T+1: Line i+1 describes trail i with three space-separated integers: lengthi , I1i , and I2i
Output
- Line 1: A single integer that is the shortest distance from intersection S to intersection E that traverses exactly N cow trails.
Sample Input
2 6 6 4——–n个点,t条边,起点s,终点e
11 4 6——–4到6有一条权值为11的边
4 4 8
8 4 9
6 6 8
2 6 9
3 8 9
Sample Output
10
求一条从s到e的经过n条边的最短路
用矩阵乘法+快速幂的思想。
A(i,j)=1代表从i到j有1条边
A(i,j)*A(i,j)=∑A(i,k)*A(k,j)
(当A(i,k)和A(k,j)都为1是才有意义)
那么A的平方代表从i到j有一条经过k的边,也就是路径为2
那么A的(k-1)次方代表路径为k
于是我们定义新的矩阵乘法
把相乘的部分改为Floyd
但是枚举k次方可能会TLE,所以用快速幂(*快速幂详见–模板–快速幂)
#include<algorithm>//floyd是通过枚举k来更新dis(i,j)所以只要枚举n-1次k就可以求得经过n条边的最短路
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
int n,t,s,e;//n头牛,t条边,起点s终点e
int f[30+10][200+10][200+10],ll;
int a[1000+10],cnt,b[200+10][200+10],ans[200+10][200+10];//a数组记录i点的映射
void pow(){ //快速幂
ll=0;
while(n>0){
if(n%2==1){//如果是奇数----ans=(ans*a)%c
memset(b,0x3f,sizeof(b));
// for(int i=0;i<=cnt;i++)********此处一定不能初始化对角线元素,因为对角线元素已经改变
// b[i][i]=0;
for(int k=1;k<=cnt;k++)
for(int i=1;i<=cnt;i++)
for(int j=1;j<=cnt;j++)
b[i][j]=min(b[i][j],min(ans[i][k]+f[ll][k][j],f[ll][i][k]+ans[k][j]));
for(int i=1;i<=cnt;i++)
for(int j=1;j<=cnt;j++)
ans[i][j]=b[i][j];
}
//a=a*a%c
ll++;
for(int k=1;k<=cnt;k++)
for(int i=1;i<=cnt;i++)
for(int j=1;j<=cnt;j++)
f[ll][i][j]=min(f[ll-1][i][k]+f[ll-1][k][j],f[ll][i][j]);
n>>=1;
}
}
int main(){
cnt=0;
memset(a,0,sizeof(a));//如果a[i]为0代表i没有映射
scanf("%d%d%d%d",&n,&t,&s,&e);
memset(ans,0x3f,sizeof(ans));
memset(f,0x3f,sizeof(f));
// for(int i=0;i<=210;i++)
// f[0][i][i]=0;********此处不能初始化对角线元素,有自环
for(int i=1;i<=200;i++)
ans[i][i]=0;
for(int i=1,x,y,z;i<=t;i++){
scanf("%d%d%d",&z,&x,&y);
if(!a[x])
a[x]=++cnt;
if(!a[y])
a[y]=++cnt;
if(f[0][a[x]][a[y]]>z){//有重边
f[0][a[x]][a[y]]=z;//无向边
f[0][a[y]][a[x]]=z;
}
}
pow();
cout<<ans[a[s]][a[e]]<<endl;
return 0;
}
/*
100 6 6 4
11 4 6
4 4 8
8 4 9
6 6 8
2 6 9
3 8 9*/