最短路
Time Limit : 5000/1000ms (Java/Other) Memory Limit : 32768/32768K (Java/Other)
Total Submission(s) : 1 Accepted Submission(s) : 0
核心思路
编辑路径矩阵
状态转移方程
首先,我们在找1到n的最短时间时,最短时间可能是1直接到n点的时间,也可能是1经过多个点再到n点的时间。
如图;求1到4的最短时间,指向4的有1,3两个点。指向3的除了4以外有1,2。而指向2的只有1。所以到达4的路径有(1)1—>4;(2)1—>2—>3—>4;(3)1—>3—>4;三条路径。而(2)和(3)两种路径实际上就是求1到3的最短时间加上3到4的最短时间。所以我们需要知道1到3的最短时间是什么。1到3的路径有(1)1—>2—>3;(2)1—>3;经比较第一条路径时间更短为5;所以1直接4的时间一个为4,经转点到达四的时间为6;经比较走1—>4这条路径时间更短。我们发现在只有一个转点k的情况下只需比较i—>k—>j 和i—>j;如果i—>k—>j 的时间小于i—>j的时间 那么就让i—>j(代表最短时间)的时间等于i—>k—>j ;用一个二维数组表示为if(time[i][j]>time[i][k]+time[k][j])time[i][j]=time[i][k]+time[k][j];
用一个n*n的表格来表示这个二维数组;竖着表示起始位置横着表示终点位置;i=j时距离为0;其中2无法直接到达1,3无法直接到达2,4无法直接到达2,2无法直接到达4所以都设为无穷大。
在只允许经过1号顶点的情况下,任意两点之间的最短路程更新为:
通过上图我们发现:在只通过1号顶点中转的情况下,3号顶点到2号顶点(time[3][2])、4号顶点到2号顶点(time[4][2])以及4号顶点到3号顶点(time[4][3])的路程都变短了。
在只允许经过1和2号顶点的情况下,任意两点之间的最短路程更新为:
通过上图得知,在相比只允许通过1号顶点进行中转的情况下,这里允许通过1和2号顶点进行中转,使得e[1][3]和e[4][3]的路程变得更短了。
同理,继续在只允许经过1、2和3号顶点进行中转的情况下,求任意两点之间的最短路程。任意两点之间的最短路程更新为:
最后允许通过所有顶点作为中转,任意两点之间最终的最短路程为:
上面的图是看一位大佬的。
核心代码:
- for(k=1;k<=n;k++)
- for(i=1;i<=n;i++)
- for(j=1;j<=n;j++)
- if(time[i][j]>time[i][k]+time[k][j])
- time[i][j]=time[i][k]+time[k][j];
下面出示我的ac代码
#include<iostream>
#define maxn 9999999;
using namespace std;
int time[101][101],i,j,k,n;
void floyd()
{
for(k=1;k<=n;k++)
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
if(time[i][k]+time[k][j]<time[i][j])
time[i][j]=time[i][k]+time[k][j];
}
int main(int argc,char* argv[])
{
int m,c,a,b;
while(cin>>n>>m)
{
if(n==m&&n==0)break;
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
{
if(i==j)time[i][j]=0;
else time[i][j]=maxn;
}
for(i=1;i<=m;i++)
{
cin>>a>>b>>c;
time[a][b]=time[b][a]=c;
}
floyd();
cout<<time[1][n]<<endl;
}
return 0;
}