题意:给定一个无向图,和两个点,求出给定两点间经过n条路的最短路。
思路分析:其实刚开始看题时想到的是dijisktla,但后来由于想不出来输出规定边数的最短路长度的方法,就放弃了。
这道题用到的是floyd,反正T<=100,我们可以准备两个数组,其中一个始终装着每个边的初始情况,这样我们每将两个矩阵计算一次,给定两点间经过的边数就会增加一次,故我们只需跑n-1次即可,这样我们就能坐等AC超时了,由于n<= 1,000,000,硬算是一定会超时的,于是我们还需要其他的优化方法。我们看着Floyd,想起来什么没有?对了,就是矩阵乘法,我们可以运用二进制拆分的方法,将n-1拆成若干个二进制位,修改原数组,再进行运算,就没有问题了。
另外,看见网上的大佬们都用到了离散化,这里我就学了一下。
代码:
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 const int N=1e6+10; 6 int n,t,s,e,sum,num[N];//num,sum用于离散化 7 struct squ{ 8 int a[510][510]; 9 squ operator * (const squ &x)const{ //重载运算符,方便快速幂 10 squ c; 11 memset(c.a,0x3f3f3f3f,sizeof(c.a)); //不能互达的边初始化为无穷 12 for(int k=1;k<=sum;++k) 13 for(int i=1;i<=sum;++i) 14 for(int j=1;j<=sum;++j) 15 c.a[i][j]=min(c.a[i][j],a[i][k]+x.a[k][j]); 16 return c; 17 } 18 }dis,ans; 19 int main(){ 20 memset(dis.a,0x3f3f3f3f,sizeof(dis.a)); 21 scanf("%d%d%d%d",&n,&t,&s,&e); 22 for(int i=1;i<=t;++i){ 23 int x,y,z; 24 scanf("%d%d%d",&x,&y,&z); 25 if(!num[y]) num[y]=++sum; //离散化 26 if(!num[z]) num[z]=++sum; 27 dis.a[num[y]][num[z]]=dis.a[num[z]][num[y]]=x; 28 } 29 n--; 30 ans=dis; 31 while(n){ 32 if(n&1) ans=ans*dis; 33 dis=dis*dis; //二进制拆分,倍增 34 n>>=1; 35 } 36 printf("%d ",ans.a[num[s]][num[e]]); 37 return 0; 38 }