最短路径问题8595
问题描述
平面上有n个点(n<=100),每个点的坐标均在-10000~10000之间。其中的一些点之间有连线。
若有连线,则表示可从一个点到达另一个点,即两点间有通路,通路的距离为两点间的直线距离。现在的任务是找出从一点到另一点之间的最短路径。
输入文件
共n+m+3行,其中:
第一行为整数n。
第2行到第n+1行(共n行) ,每行两个整数x和y,描述了一个点的坐标。
第n+2行为一个整数m,表示图中连线的个数。
此后的m 行,每行描述一条连线,由两个整数i和j组成,表示第i个点和第j个点之间有连线。
最后一行:两个整数s和t,分别表示源点和目标点。
输出
仅一行,一个实数(保留两位小数),表示从s到t的最短路径长度。
样例输入
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
题解
一道不折不扣的大水题…(所以我为什么要写水题呢…?当然是熟悉下博客功能……)
首先是一个尴尬的问题,两点间距离公式。忘掉了?戳->http://t.cn/Efz0mN8
这里采用的是floyed算法。(什么是floyed?戳->https://www.cnblogs.com/Uninstalllingyi/p/10417446.html)
需要注意的只是初始化问题和数据类型、小数位数保留问题。总之问题不大。
1 #include<iostream> 2 #include<cmath> 3 #include<cstring> 4 //floyed 5 using namespace std; 6 const int MAXN=101; 7 double map[MAXN][MAXN]; 8 struct position{ 9 int x; 10 int y; 11 }pos[MAXN]; 12 double dist(int a,int b){ 13 double ans; 14 double x=pos[a].x-pos[b].x; 15 double y=pos[a].y-pos[b].y; 16 ans=sqrt(x*x+y*y); 17 return ans; 18 } 19 int main(){ 20 int n; 21 cin>>n; 22 for(int i=1;i<=n;i++){ 23 cin>>pos[i].x>>pos[i].y; 24 } 25 int m; 26 cin>>m; 27 memset(map,127,sizeof(map)); 28 int p1,p2; 29 for(int i=1;i<=m;i++){ 30 cin>>p1>>p2; 31 map[p1][p2]=map[p2][p1]=dist(p1,p2); 32 } 33 cin>>p1>>p2;//我实在是懒得再开变量了… 34 for(int k=1;k<=n;k++){ 35 for(int i=1;i<=n;i++){ 36 for(int j=1;j<=n;j++){ 37 if(i!=k&&i!=j&&j!=k){ 38 map[i][j]=min(map[i][j],map[i][k]+map[k][j]); 39 } 40 } 41 } 42 } 43 printf("%.2f",map[p1][p2]); 44 }
然后逐渐发现floyed算法并不够优秀。
1 #include<iostream> 2 #include<cmath> 3 #include<cstring> 4 using namespace std; 5 //Bellman-Ford 6 const int MAXN=105; 7 struct edge{ 8 int s,e; 9 double w; 10 }edges[MAXN*(MAXN-1)/2]; 11 int n,m,idx; 12 double dis[MAXN],map[MAXN][2]; 13 void addedge(int u,int v,double w){ 14 edges[++idx].s=u;edges[idx].e=v;edges[idx].w=w; 15 edges[++idx].s=v;edges[idx].e=u;edges[idx].w=w; 16 } 17 double dist(int a,int b){ 18 double x=map[a][0]-map[b][0]; 19 double y=map[a][1]-map[b][1]; 20 return sqrt(x*x+y*y); 21 } 22 void bellman(){ 23 while(--n){ 24 bool b=0; 25 for(int i=1;i<=idx;i++){ 26 if(dis[edges[i].e]>dis[edges[i].s]+edges[i].w){ 27 dis[edges[i].e]=dis[edges[i].s]+edges[i].w; 28 b=1; 29 } 30 } 31 if(!b){ 32 break; 33 } 34 } 35 } 36 int main(){ 37 cin>>n; 38 for(int i=1;i<=n;i++){ 39 cin>>map[i][0]>>map[i][1]; 40 } 41 cin>>m; 42 int a,b; 43 for(int i=1;i<=m;i++){ 44 cin>>a>>b; 45 addedge(a,b,dist(a,b)); 46 } 47 int s,e; 48 cin>>s>>e; 49 for(int i=1;i<=n;i++){ 50 dis[i]=0x3f3f3f3f; 51 } 52 dis[s]=0; 53 bellman(); 54 printf("%.2f ",dis[e]); 55 }
所以来了一波福特算法。
然后发觉还不够过瘾,
1 #include<iostream> 2 #include<cmath> 3 #include<cstring> 4 using namespace std; 5 const int MAXN=500; 6 const double maxx=1e18; 7 double minx; 8 //dijkstra 9 double map[MAXN][MAXN]; 10 int point[MAXN][3]; 11 bool vis[MAXN]; 12 double dis[MAXN]; 13 double dist(int a,int b){ 14 double ans; 15 double x=point[a][1]-point[b][1]; 16 double y=point[a][2]-point[b][2]; 17 ans=sqrt(x*x+y*y); 18 return ans; 19 } 20 int main(){ 21 memset(map,0x7f,sizeof(map)); 22 int n; 23 cin>>n; 24 int x,y; 25 for(int i=1;i<=n;i++){ 26 cin>>point[i][1]>>point[i][2]; 27 } 28 int m; 29 cin>>m; 30 for(int i=1;i<=m;i++){ 31 cin>>x>>y; 32 map[x][y]=map[y][x]=dist(x,y); 33 } 34 int s,t; 35 cin>>s>>t; 36 for(int i=1;i<=n;i++){ 37 dis[i]=map[s][i]; 38 } 39 vis[s]=true;dis[s]=0; 40 for(int i=1,k=0;i<=n-1;i++){ 41 minx=maxx; 42 for(int j=1;j<=n;j++){ 43 if(!vis[j]&&dis[j]<minx){ 44 minx=dis[j]; 45 k=j; 46 } 47 } 48 if(k==0){ 49 break; 50 } 51 vis[k]=true; 52 for(int j=1;j<=n;j++){ 53 dis[j]=min(dis[j],dis[k]+map[k][j]); 54 } 55 } 56 printf("%.2lf",dis[t]); 57 }
dijkstra算法。
这些算法都在本博里有作介绍。(目前跑得最快的是福特)