zoukankan      html  css  js  c++  java
  • 【图】最短路径——Floyed算法和Dijkstra算法

    最短路径问题(floyed.cpp dijkstra.cpp)


    题目描述
    平面上有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

    #------------------------------------------------------------------------------#

    最短路径也是有很多方法的,这里就讲讲Floyed和Dijkstra。

    Floyed:

    这种算法比较好理解,且可以求任意两点间的最短路径,但速度很慢,为O(N^3)

    首先,需要k[i][j]存从第i点到第j点间的最短路径,如果它们不相连,则为∞(无穷大)(在这里可以设为0x7fffffff,0x表示后面的数为16进制,7fffffff即是16进制数,化为10进制等于2147483647)。

    然后需要3层循环,第一层:需要经过的点p,第二、三层起点i和终点j,然后就开始推,很像动规的,“状态转移方程”为:k[i][j]=min(k[i][j],k[i][p]+k[p][j])

    这样不用考虑两点没联通的情况吗?之前的∞就有作用了,如果两点没联通的话是赋不了值的。

    代码Floyed

    #include<cstdio>
    #include<cmath>
    struct p
    {
    	int x,y;
    }a[102];//这个结构体是存平面直角坐标系的
    int f[102][102];
    double k[102][102];
    int n,m,hhd;
    int main()
    {
    	//freopen("floyed.in","r",stdin);
    	//freopen("floyed.out","w",stdout);//文件输入输出
    	int b,e;
    	scanf("%d",&n);
    	for(int i=1;i<=n;i++)
    		scanf("%d%d",&a[i].x,&a[i].y);
    	scanf("%d",&m);
    	for(int i=1;i<=m;i++)
    	{
    		int x,y;
    		scanf("%d%d",&x,&y);
    		f[x][y]=f[y][x]=1;//邻接数组标记
    	}
    	scanf("%d%d",&b,&e);
    	for(int i=1;i<=n;i++)
    		for(int j=1;j<=n;j++)
    			if(f[i][j])//如果两点有连接
    				k[i][j]=sqrt(pow(a[i].x-a[j].x,2.0)+pow(a[i].y-a[j].y,2.0));//求两点距离,存入k数组
    			else
    				k[i][j]=0x7fffffff;//反之则设为极大值
    	for(int p=1;p<=n;p++)
    		for(int i=1;i<=n;i++)
    			for(int j=1;j<=n;j++)
    				if(k[i][j]>k[i][p]+k[p][j])
    					k[i][j]=k[i][p]+k[p][j];//开始算法
    	printf("%.2lf",k[b][e]);//输出从起点(b)到终点(e)的最短路径
    	return 0;
    }
    

                                   ----我只是个小分割线----

    Dijkstra:

    此算法较(只是较前一种)快,时间复杂度为O(N^2),注意,它不能处理负边权的情况

    而且这个只能求从一个起点(单源点)到其他任何点的距离,但解决这道题足够了。

    一个一维数组dis[i]表示起点到i点的最短距离,k数组与上同,还需要一个bool数组判断该点是否用过。

    思路:从起点到某个点一定会经过一个及以上的“中间点”,可以发现从起点到i点的最短路径中的每一个“中间点”到起点的距离都是相等的,就像动态规划的“最优子结构”性质,所以只要找出每个点的最短路径,即可知道起点到终点的最短路径。

    为什么不能处理负边权呢?


    如图,假如想要从1到3,最短的显然为1->2->3,共-2,但Dijkstra算法会先选择直接到3,因为这样为1,所以答案错误。

    代码(Dijkstra):

    #include<cstdio>
    #include<cmath>
    #include<cstring>
    struct p
    {
    	int x,y;
    }a[102];
    int _f[102][102];
    bool f[102];
    double k[102][102],dis[102];
    int n,m;
    int main()
    {
    	//freopen("dijkstra.in","r",stdin);
    	//freopen("dijkstra.out","w",stdout);
    	int b,e;
    	scanf("%d",&n);
    	for(int i=1;i<=n;i++)
    		scanf("%d%d",&a[i].x,&a[i].y);
    	scanf("%d",&m);
    	for(int i=1;i<=m;i++)
    	{
    		int x,y;
    		scanf("%d%d",&x,&y);
    		_f[x][y]=_f[y][x]=1;
    	}
    	for(int i=1;i<=n;i++)
    		for(int j=1;j<=n;j++)
    			if(_f[i][j])
    				k[i][j]=sqrt(pow(a[i].x-a[j].x,2.0)+pow(a[i].y-a[j].y,2.0));
    			else
    				k[i][j]=0x7fffffff;//以上与Floyed相同
    	scanf("%d%d",&b,&e);
    	f[b]=1;
    	for(int i=1;i<=n;i++)
    		dis[i]=k[b][i];//将距离存进去
    	for(int i=1;i<=n-1;i++)
    	{
    		int p=0x7fffffff,w=0;//p为当前最小值,w为“中间点”下标
    		for(int j=1;j<=n;j++)
    			if(f[j]==0&&dis[j]<p)
    			{
    				w=j;
    				p=dis[j];//更新最小值
    			}//查找“中间点”
    		if(w==0)
    			break;//如果全部没有,则表示找完了
    		f[w]=1;//标记此点已用
    		for(int j=1;j<=n;j++)
    			if(dis[w]+k[w][j]<dis[j])
    				dis[j]=dis[w]+k[w][j];//开始找进过w的最小值
    	}
    	printf("%.2lf",dis[e]);//输出
    	return 0;
    }
    


                                                                                                                                                                               By WZY

  • 相关阅读:
    ubuntu下文件安装与卸载
    webkit中的JavaScriptCore部分
    ubuntu 显示文件夹中的隐藏文件
    C语言中的fscanf函数
    test
    Use SandCastle to generate help document automatically.
    XElement Getting OuterXML and InnerXML
    XUACompatible meta 用法
    Adobe Dreamweaver CS5.5 中文版 下载 注册码
    The Difference Between jQuery’s .bind(), .live(), and .delegate()
  • 原文地址:https://www.cnblogs.com/LinqiongTaoist/p/7203760.html
Copyright © 2011-2022 走看看