题目描述
平面上有n个点(n<=100),每个点的坐标均在-10000~10000之间。其中的一些点之间有连线。若有连线,则表示可从一个点到达另一个点,即两点间有通路,通路的距离为两点间的直线距离。现在的任务是找出从一点到另一点之间的最短路径。
输入
第1行:1个整数n
第2..n+1行:每行2个整数x和y,描述了一个点的坐标
第n+2行:1个整数m,表示图中连线的数量
接下来有m行,每行2个整数i和j,表示第i个点和第j个点之间有连线
最后1行:2个整数s和t,分别表示源点和目标点
输出
第1行:1个浮点数,表示从s到t的最短路径长度,保留2位小数
样例输入
5
0 0
2 0
2 2
0 2
3 1
5
1 2
1 3
1 4
2 5
3 5
1 5
样例输出
3.41
--------------------------------------------------------------------
我们可以用勾股定理,将每两个点的权值算出来(两点之间没有边的为∞),完成构图。
---------------------------------------------------------------------
求最短路的四种算法(u[i][j]为连接i与j的边的权值, dis[i][j]为从i到j的最短路径长度,dis[i]为从起点至i的最短路径,s为起点,e为终点):
一、Floyd算法
算法步骤:
1、初始化。使dis[i][j] = u[i][j];
2、依次枚举中间点k;
3、如果dis[i][j] > dis[i][k] + dis[k][j],则将dis[i][j]替换;
4、dis[s][e]为最终答案。
注意:外层循环一定要枚举k。
for(int k = 1; k <= n; k++)
{
for(int i = 1; i <= n; i++)
{
for(int j = 1; j <= n; j++)
dis[i][j] = min(dis[i][j], dis[i][k] + dis[k][j]);
}
}
二、Dijkstra算法
算法步骤:
1、初始化。使dis[i] = u[s][i];
2、从所有未被访问的节点中选择dis最小的那一个;
3、重新计算dis[i]的最短路径长;
4、给现在被选中的节点打上标记。
5、dis[e]为最终答案。
for(int i = 1; i <= n; i++)
{
int p = 0, j, mins = 1 << 30;
for(j = 1; j <= n; j++)
{
if(!v[j] && dis[j] < mins)
p = j, mins = dis[j];
}
if(!p)
return 0;
v[p] = 1;
for(j = 1; j <= n; j++)
dis[j] = min(dis[j], dis[p] + u[p][j]);
}
三、Bellman-Ford算法
算法步骤:
1、给每一个点编号;
2、依次每句每一条边,更新dis[i]的最短距离;
3、dis[e]为最终答案。
for(int i = 1; i <= n; i++)
{
for(int j = 1; j <= E; j++)
dis[v] = min(dis[v], dis[u] + w[j]); //u和p表示gaibian
}
四、SPFA算法
算法步骤:
1、将目前的点加入队列;
2、取出队首元素;
3、若通过该点可更新另一个点dis[i]的值,则进行4,否则执行3,直到连接该点的所有边枚举完;
4、若该点不在队列中,则将该点加入队列;
5、dis[e]为最后答案。
for(int i = 1; i <= n; i++)
{
int p = queue.front();
queue.pop();
v[p] = 0;
for(int j = 1; j <= n; j++)
{
if(dis[j] > dis[p] + w[p][j])
{
dis[j] = dis[p] + w[p][j];
if(!v[j])
{
v[j] = 1;
queue.push(j);
}
}
}