【图论】【最短路】最短路径问题(三种方法)

Description

平面上有n个点(N<=100),每个点的坐标均在-10000~10000之间。其中的一些点之间有连线。若有连线,则表示可从一个点到达另一个点,即两点间有通路,通路的距离为两点直线的距离。现在的任务是找出从一点到另一点之间的最短路径。

Input

共有n+m+3行,其中:
第一行为一个整数n。
第2行到第n+1行(共n行),每行的两个整数x和y,描述一个点的坐标(以一个空格隔开)。
第n+2行为一个整数m,表示图中的连线个数。
此后的m行,每行描述一条连线,由两个整数I,j组成,表示第i个点和第j个点之间有连线。
最后一行:两个整数s和t,分别表示源点和目标点。

Output

输出文件short.out仅一行,一个实数(保留两位小数),表示从S到T的最短路径的长度。

Sample Input

5
0 0
2 0
2 2
0 2
3 1
5
1 2
1 3
1 4
2 5
3 5
1 5

Sample Output

3.41

思路(Floyed)

建图

首先读入好坐标,然后求出每一条边的权值,这样就建好图了
求两个坐标之间的距离公式:
s q r t ( p o w ( d o u b l e ( a [ x ] [ 1 ] a [ y ] [ 1 ] ) , 2 ) + p o w ( d o u b l e ( a [ x ] [ 2 ] a [ y ] [ 2 ] ) , 2 ) ) sqrt(pow(double(a[x][1]-a[y][1]),2)+pow(double(a[x][2]-a[y][2]),2)) (勾股定理)

求答案

F l o y e d Floyed 算法求出图中任意两个点之间的距离,最后输出要求的两个点的距离就OK了
这道题本来是图论,被我硬生生打成DP了

代码

#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
using namespace std;
int a[101][5],n,m;
double f[101][101];
int main()
{
	memset(f,0x7f,sizeof(f));  
	scanf("%d",&n);
	for (int i=1;i<=n;i++) scanf("%d%d",&a[i][1],&a[i][2]);
	scanf("%d",&m);
	int x,y;
	for (int i=1;i<=m;i++)
	 {
	 	scanf("%d%d",&x,&y);
	 	f[x][y]=f[y][x]=sqrt(pow(double(a[x][1]-a[y][1]),2)+pow(double(a[x][2]-a[y][2]),2));//算距离
	 }
	 int z,c;
	scanf("%d%d",&z,&c);//要求的两个点
	for (int k=1;k<=n;k++)//枚举i和j之间的点
	 for (int i=1;i<=n;i++)
	  for (int j=1;j<=n;j++){
	   if (i!=k&&i!=j&&j!=k&&f[i][j]>f[i][k]+f[k][j])
	    f[i][j]=f[i][k]+f[k][j];
     }
    printf("%.2lf\n",f[z][c]);//保留两位小数
}

思路(Dijkstra)

建图

首先读入好坐标,然后求出每一条边的权值,这样就建好图了
求两个坐标之间的距离公式:
s q r t ( p o w ( d o u b l e ( a [ x ] [ 1 ] a [ y ] [ 1 ] ) , 2 ) + p o w ( d o u b l e ( a [ x ] [ 2 ] a [ y ] [ 2 ] ) , 2 ) ) sqrt(pow(double(a[x][1]-a[y][1]),2)+pow(double(a[x][2]-a[y][2]),2)) (勾股定理)

求答案

用Dijkstra算法从起点开始去枚举每一个点,最后求出答案。

代码

#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
using namespace std;
int n,a[201][3],m;
bool b[101];
double c[101],f[101][101];
int main()
{
	memset(f,0x7f,sizeof(f));
	scanf("%d",&n);
	for (int i=1;i<=n;i++)
	 scanf("%d%d",&a[i][1],&a[i][2]);
	double maxx=1e30;
	scanf("%d",&m); int x,y;
    for (int i=1;i<=m;i++){
    	scanf("%d%d",&x,&y);
    	double l=a[x][1]-a[y][1];
    	double r=a[x][2]-a[y][2]; 
		f[y][x]=f[x][y]=sqrt(l*l+r*r);
    }	 
    int s,t;
    scanf("%d%d",&s,&t);
    memset(b,false,sizeof(b));
    for (int i=1;i<=n;i++)
     c[i]=f[s][i];
	b[s]=true; c[s]=0;
	for (int i=1;i<=n;i++)
	 {
	     double minx=maxx;
	 	 int k=0;
	 	 for (int j=1;j<=n;j++)
	 	  if (b[j]==false&&c[j]<double(minx)) {
	 	  	minx=min(c[j],minx);
	 	    k=j;
	 	  }//在所有与起点直接相连的点中找一个距离最短的
	 	 if (k==0) break;
	 	 b[k]=true;
	 	 for (int j=1;j<=n;j++){
	       if (c[k]+f[k][j]<c[j]&&b[j]==false)
	        c[j]=c[k]+f[k][j];//更新路径长度
	     }
	 } 
	 printf("%.2lf",c[t]);
	 return 0;
}

思路(Ford)

建图还是一样,然后用Ford算法来编写代码就可以了
具体↓↓↓

代码

#include<cstdio>
#include<iostream>
#include<cmath>
using namespace std;
double dis[1001],w[1001];//dis表示最短路,w表示距离
int  a[1001][3],n,m,x,y,k,f[1001][3];
int main()
{
	memset(dis,0x7f,sizeof(dis));
	memset(f,0x7f,sizeof(f)); 
    scanf("%d",&n);
    for (int i=1;i<=n;i++) 
     	scanf("%d%d",&a[i][1],&a[i][2]);
    scanf("%d",&m);
    for (int i=1;i<=m;i++)
     {
     	scanf("%d%d",&x,&y);
     	double l=a[x][1]-a[y][1];
     	double r=a[x][2]-a[y][2];
     	w[i]=sqrt(l*l+r*r);//建图
		 f[i][1]=x; f[i][2]=y;//记录点的位置
     }
     int s,t; 
     scanf("%d%d",&s,&t);
     dis[s]=0;
     for (int i=1;i<=n;i++)
      for (int j=1;j<=m;j++)
      {
      	if (dis[f[j][1]]+w[j]<dis[f[j][2]]) dis[f[j][2]]=dis[f[j][1]]+w[j];//更新最短路(从i到j)
      	if (dis[f[j][2]]+w[j]<dis[f[j][1]]) dis[f[j][1]]=dis[f[j][2]]+w[j];//更新最短路(从j到i)
      }
      printf("%.2lf",dis[t]);
      return 0;
} 

猜你喜欢

转载自blog.csdn.net/LTH060226/article/details/86517640