洛谷P2886 [USACO07NOV]Cow Relays G

 

 题意:给定一个无向图,和两个点,求出给定两点间经过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\n",ans.a[num[s]][num[e]]);
37     return 0;
38 }
View Code

 

posted @ 2020-04-28 15:15  19502-李嘉豪  阅读(171)  评论(0编辑  收藏  举报