思想
倍增:
这种方式在数学上称之为矩阵乘法;
#include<iostream>
#include<algorithm>
#include<cstring>
#include<map>
using namespace std;
const int N=1010;
int K,n,m,S,E;
int g[N][N];//开始为只经过一条边的数组
int res[N][N];//答案数组
void floyd(int a[][N],int b[][N],int c[][N])
{
static int temp[N][N];//temp数组作为b数组和c组数相乘的结果
memset(temp,0x3f,sizeof temp);
for(int k=1;k<=n;k++)
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
temp[i][j]=min(temp[i][j],b[i][k]+c[k][j]);
memcpy(a,temp,sizeof temp); //复制得到结果
}
void qmi()//快速幂套floyd
{
memset(res,0x3f,sizeof res);
for(int i=1;i<=n;i++) res[i][i]=0;
while(K)
{
if(K&1) floyd(res,res,g);//更新答案数组,即res=res*g
floyd(g,g,g);//将g数组倍增,即g=g*g
K>>=1;
}
}
int main()
{
cin>>K>>m>>S>>E;
map<int,int> id;
memset(g,0x3f,sizeof g);
//因为g数组必须走过一条边,所以g[i][i]不初始化为0,除非i->i之间有边
id[S]=++n,id[E]=++n;
S=id[S],E=id[E];
//离散化过程,因为题目中给的编号并不是从1开始而是随机的;
for(int i=1;i<=m;i++)
{
int a,b,c;
cin>>c>>a>>b;
if(!id.count(a)) id[a]=++n;
if(!id.count(b)) id[b]=++n;
a=id[a],b=id[b];
g[a][b]=g[b][a]=min(g[a][b],c);
}
qmi();
printf("%d",res[S][E]);//输出答案
return 0;
}
如果有问题,欢迎在下方指出
大佬写得很详细,其他都没看懂,翻到这篇解答懂了。。。(o´ω`o)ノ
写的真的棒!
orz
%%%
😍
orz
为什么floyd中要开一个temp数组,不能直接用a数组吗,就是把里面含有temp的位置都改为a
因为要严格控制最短路中边的数量,原版floyd算法可以直接用原数组是因为它没有边数限制,如果直接在原数组上做的话,可能会重复更新(利用本轮dp得到的新结果来继续优化这一轮dp),这样的话会破坏我们原本对于边数的限制。
这里需要注意的是由于数组时按址调用,所以对于floyd(res,res,g)这个函数,a与b是相同的一个东西,只是看起来形式不一样罢了,对于a的修改,b也会进行修改,这是不正确的,会导致往后的程序(对数组的更新)发生错误,所以我们才要使用临时数组temp记录中间结果。同样的对于floyd(g,g,g)也是如此
大佬写的真的好%%%
s = e的话就错了吧
$S = E$情况下也对,例如$1 \rightarrow 2 \rightarrow 1$, $dp[1][1][2] + dp[1][2][1]$ 即为解,另外题目没有考虑边数为$0$ 的情况(即自环), 因为题目保证了$N \ge 2$,如果存在自环也不会影响结果 例如$1 \rightarrow 2 \rightarrow 2 \rightarrow 3$ 即为$dp[2][1][2] + dp[1][2][3]$
$S = E$情况下也对,例如$1 \rightarrow 2 \rightarrow 1$, $dp[1][1][2] + dp[1][2][1]$ 即为解,另外题目没有考虑边数为$0$ 的情况(即自环), 因为题目保证了$N \ge 2$,如果存在自环也不会影响结果 例如$1 \rightarrow 2 \rightarrow 2 \rightarrow 3$ 即为$dp[2][1][2] + dp[1][2][3]$
tql
tql
要是上一次没更新怎么办 就是g[i][k]距离本来应该是2条路的 上一次没路径更新 实际上是一条路的
floyd(g, g, g)这不是每次都要更新吗
看懂了,感谢感谢%%%
看到这里就清楚了
Orz
感谢,写的很清楚
tql,谢谢大佬
懂了 !!! tql
有点不明白的就是res[s][e]为啥是刚好经过k条边 他不会重复嘛
类似于快速幂的处理方式,你再好好理解下qmi函数部分就应该会get到啦~
我来给大佬评论一下 至少我是看这个才看懂的 感谢大佬