题目大意
给定n个点,m条无向边,给定起点和终点,问经过k条路径能从起点走向终点的最短路程
解法
题目点数较少,但是范围较大,可以先用离散化将点从新映射到较小范围,然后使用Floyd算法为核心思想解决问题
具体操作证明
ans[i][j][x]=min(ans[i][k][x-y]+ans[k][j][y],ans[i][j][k])
i,j表示路程的起点和终点,x表示中间经过了几条边
上式显然满足交换律,故可以使用类似矩阵快速幂的方法实现
代码如下:
#include <bits/stdc++.h>
using namespace std;
map<int,int> lsh;
int temp[110][110];
int ans[110][110];
int mp[110][110];
int n,t,s,e,cnt;
void fast_power(int x)
{
memset(ans,0x3f,sizeof(ans));
for(int i=1;i<=cnt;i++)
ans[i][i]=0;
while(x)
{
if(x%2)
{
memset(temp,0x3f,sizeof(temp));
for(int k=1; k<=cnt; k++)
for(int i=1; i<=cnt; i++)
for(int j=1; j<=cnt; j++)
temp[i][j]=min(ans[i][k]+mp[k][j],temp[i][j]);
for(int i=1; i<=cnt; i++)
for(int j=1; j<=cnt; j++)
ans[i][j]=temp[i][j];
}
memset(temp,0x3f,sizeof(temp));
for(int k=1; k<=cnt; k++)
for(int i=1; i<=cnt; i++)
for(int j=1; j<=cnt; j++)
temp[i][j]=min(mp[i][k]+mp[k][j],temp[i][j]);
for(int i=1; i<=cnt; i++)
for(int j=1; j<=cnt; j++)
mp[i][j]=temp[i][j];
x>>=1;
}
}
int main()
{
scanf("%d%d%d%d",&n,&t,&s,&e);
memset(mp,0x3f,sizeof(mp));
for(int i=1,u,v,w; i<=t; i++)
{
scanf("%d%d%d",&w,&u,&v);
if(lsh[u]==0)
lsh[u]=++cnt;
if(lsh[v]==0)
lsh[v]=++cnt;
mp[lsh[u]][lsh[v]]=min(w,mp[lsh[u]][lsh[v]]);
mp[lsh[v]][lsh[u]]=min(w,mp[lsh[v]][lsh[u]]);
}
s=lsh[s];
e=lsh[e];
fast_power(n);
printf("%d",ans[s][e]);
return 0;
}