这题很好的综合了图论和数论的知识来解题,这种转化综合的思维我要好好地加强训练才行……其实这里明白到一点就可以很好地知道它们之间是怎么转化的,当map[i][j]表示i到j的最短路径,map[j][k]表示j到k的最短路径,且是经过n条路时,那么i到k的最短距离且经过2*n条路就一定是map[i][j]+map[j][k]了!
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
#define inf 1000000000
#define N 205
int n,num,map[N][N],dis[N][N]; //dis[i][j]表示从i到j经过k条路的最短距离
void slove()
{
while(n)
{
int ans[num][num];
if(n&1)
{
for(int i=0;i<num;i++)
{
for(int j=0;j<num;j++)
{
ans[i][j]=inf;
}
}
for(int i=0;i<num;i++)
{
for(int j=0;j<num;j++)
{
for(int k=0;k<num;k++)
{
ans[i][k]=min(ans[i][k],dis[i][j]+map[j][k]);
}
}
}
for(int i=0;i<num;i++)
{
for(int j=0;j<num;j++)
{
dis[i][j]=ans[i][j];
}
}
}
for(int i=0;i<num;i++)
{
for(int j=0;j<num;j++)
{
ans[i][j]=inf;
}
}
for(int i=0;i<num;i++)
{
for(int j=0;j<num;j++)
{
for(int k=0;k<num;k++)
{
ans[i][k]=min(ans[i][k],map[i][j]+map[j][k]);
}
}
}
for(int i=0;i<num;i++)
{
for(int j=0;j<num;j++)
{
map[i][j]=ans[i][j];
}
}
n>>=1;
}
}
int main()
{
//freopen("a.txt","r",stdin);
int t,s,e;
while(scanf("%d%d%d%d",&n,&t,&s,&e)!=EOF)
{
int vis[5*N];
memset(vis,-1,sizeof(vis));
for(int i=0;i<N;i++)
{
for(int j=0;j<N;j++)
{
map[i][j]=dis[i][j]=inf;
dis[i][i]=0;
}
}
num=0;
while(t--)
{
int l,x,y;
scanf("%d%d%d",&l,&x,&y);
if(vis[x]==-1)vis[x]=num++; //连续化节点编号
if(vis[y]==-1)vis[y]=num++;
map[vis[x]][vis[y]]=map[vis[y]][vis[x]]=l;
}
slove();
printf("%d\n",dis[vis[s]][vis[e]]);
}
return 0;
}
本文深入探讨了将图论和数论相结合的方法,通过实例解析如何利用映射矩阵解决最短路径问题,强调了思维转换的重要性,并提供了一种高效的算法实现方式。
1888

被折叠的 条评论
为什么被折叠?



