图论的题也刷了不少了,但是近期才发现前面的一些dij什么的都忘记怎么写了,甚至分不清楚dij和spfa的区别了…所以想到这里做一些简单图论算法归纳。主要涉及的算法有:Floyd算法,dijkstra算法,spfa算法,prim算法和kruskal(其实这两个就是最小生成树算法),以及一维,二维的并查集算法(抱歉萌新最近也就学了这些算法大佬们见笑了QAQ)。
欧克!let’s begin !
首先,先说说几个算法中最简单的算法,floyd算法.
其实这个算法,就是依据动态规划原理,枚举出jk中间的一个点i以作为jk连接的桥梁,从而递推出任意两个点直接距离的最小值。有人问我i,j,k三个循环为什么不能调换位置,原因很简单,就是因为枚举ij之间的点k的时候只要用到前面的结论f(ji)和f(ik)的,所以ij必须是最快更新的一个,后面才能够用到。
虽然代码简单,但是时间复杂度o(n3),一不留神就超时了,注意数据。代码如下:
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
for(int k=1;k<=n;k++)
{
if(g[j][i]+g[i][k]<g[j][k])
g[j][k]=g[j][i]+g[i][k];//先算出各个点之间的权值情况,前提是已经全部初始化gij=+∞,具体大小判断得依据题意
}
dij算法.
原理:
1.先标记起点,然后从起点出发,得出到各个点的最小距离。
2.再每次找出离起点最近(并且之前还没有讨论过)的那个点,从这个点出发,将前面得到的起点到各个点的最短路径和以这个点为中介点,再到各个点的距离大小作比较,去最小值。时间复杂度o(n2)。
代码如下:
int i,j,t,flag[N],dis[N],g[N][N];
void dij()
{
for(i=1;i<=t-1;i++)//起点不用讨论最后一个
{
int maxx=2e9,now=0;//最小值和当前最小值位置
for(j=1;j<=t;j++)
{
if(!flag[j])//如果j未被讨论过
{
if(dis[j]<maxx)