Floyd 算法小结 

By Wine93 2013.11

1. Floyd算法简介

Floyd算法利用动态规划思想可以求出任意2点间的最短路径,时间复杂度为O(n^3),对于稠密图, 效率要高于执行|V|次Dijkstra算法.

核心代码如下:

for(k=1;k<=n;k++)

for(i=1;i<=n;i++)

for(j=1;j<=n;j++)

dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);

相关应用 : 有向图:①求任意2点间最短路径  ②求最小环(可判断负圈,检查dis[i][i])   ③求传递闭包

无向图:(无负权边): ①求任意2点间最短路径  ②求最小环

注意:对于有负权边的无向图,会出现很多意想不到的错误,请谨慎使用floyd。

2. 个人心得

对于floyd,我认为最重要的是理解k循环这层,每枚举一个k,代表下面代表的点对(i,j)之间的 最短路有可能会通过k这点而变小,也就是说在i到j的这条简单路径上插上k这个点,有可能会使路径长度变小。还有就是floyd求出来的最短路径肯定是简单路径(无向图)

关于可Floyd解的题其顶点数都比较小,根据这点会给我们一点暗示.

如果要输出floyd所求相关路径,我们可以记录mid[i][j](表示i到j这条路径中插入的点k),这样通过不断递归,就可以求出整条路径

3. Floyd算法的应用举例

(1) 求无向图最小环 

HDU 1599 find the mincost route

# include<cstdio>
# include<cstring>
# include<algorithm>
using namespace std; # define INF <<
# define N int mat[N][N],dis[N][N];
int minloop; void floyd(int n)
{
int i,j,k;
for(k=;k<=n;k++)
{
for(i=;i<=n;i++)
for(j=;j<=n;j++)
if(i!=j&&i!=k&&j!=k&&dis[i][j]+mat[j][k]+mat[k][i]<minloop)
minloop=dis[i][j]+mat[j][k]+mat[k][i];
for(i=;i<=n;i++)
for(j=;j<=n;j++)
dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
}
} void init(int n)
{
int i,j;
minloop=INF;
for(i=;i<=n;i++)
for(j=;j<=n;j++)
mat[i][j]=mat[j][i]=dis[i][j]=dis[j][i]=INF;
} int main()
{
// freopen("in.txt","r",stdin);
int i,n,m,u,v,w;
while(scanf("%d%d",&n,&m)!=EOF)
{
init(n);
for(i=;i<=m;i++)
{
scanf("%d%d%d",&u,&v,&w);
if(w<mat[u][v])
mat[u][v]=mat[v][u]=dis[u][v]=dis[v][u]=w;
}
floyd(n);
if(minloop==INF) printf("It's impossible.\n");
else printf("%d\n",minloop);
}
return ;
}

HDU 1599

POJ 1734 Sightseeing trip(需输出最小环)

# include<cstdio>
# include<cstring>
# include<vector>
# include<algorithm>
using namespace std; # define pb push_back
# define INF <<
# define N int mat[N][N],dis[N][N],mid[N][N],minloop;
vector<int> vec; void dfs(int l,int r)
{
if(mid[l][r]==-) return;
dfs(l,mid[l][r]);
vec.pb(mid[l][r]);
dfs(mid[l][r],r);
} void floyd(int n)
{
int i,j,k;
for(k=;k<=n;k++)
{
for(i=;i<k;i++)
for(j=i+;j<k;j++)
{
if(dis[i][j]+mat[j][k]+mat[k][i]<minloop)
{
minloop=dis[i][j]+mat[j][k]+mat[k][i];
vec.clear();
vec.pb(i);
dfs(i,j);
vec.pb(j);
vec.pb(k);
}
}
for(i=;i<=n;i++)
for(j=;j<=n;j++)
{
if(dis[i][k]+dis[k][j]<dis[i][j])
{
dis[i][j]=dis[i][k]+dis[k][j];
mid[i][j]=k;
}
}
}
} void init(int n)
{
int i,j;
minloop=INF;
for(i=;i<=n;i++)
for(j=;j<=n;j++)
mat[i][j]=dis[i][j]=INF,mid[i][j]=-;
vec.clear();
} int main()
{
//freopen("in.txt","r",stdin);
int i,j,n,m,u,v,w;
while(scanf("%d%d",&n,&m)!=EOF)
{
init(n);
for(i=;i<=m;i++)
{
scanf("%d%d%d",&u,&v,&w);
if(w<mat[u][v])
dis[u][v]=dis[v][u]=mat[u][v]=mat[v][u]=w;
}
floyd(n);
if(minloop==INF)
{
printf("No solution.\n");
continue;
}
printf("%d",vec[]);
for(i=;i<vec.size();i++)
printf(" %d",vec[i]);
printf("\n");
}
return ;
}

POJ 1734

相关证明理解请参考下面博客,讲解的非常好:

http://www.kaixinwenda.com/article-aclion-8074848.html

(2)判断有向图是否有正环

POJ 2240 Arbitrage

# include<cstdio>
# include<cstring>
# include<string>
# include<map>
# include<algorithm>
using namespace std; # define N
double dis[N][N]; void floyd(int n)
{
int i,j,k;
for(k=;k<=n;k++)
for(i=;i<=n;i++)
for(j=;j<=n;j++)
dis[i][j]=max(dis[i][j],dis[i][k]*dis[k][j]);
} void init(int n)
{
int i,j;
for(i=;i<=n;i++)
for(j=;j<=n;j++)
dis[i][j]=(i==j)?:;
} int main()
{
// freopen("in.txt","r",stdin);
map<string,int> Hash;
int i,n,m,num,flag,cas=,u,v;
char s1[N],s2[N];
double d;
while(scanf("%d",&n)!=EOF&&n)
{
Hash.clear();
flag=num=;
init(n);
for(i=;i<=n;i++)
{
scanf("%s",s1);
Hash[s1]=++num;
}
scanf("%d",&m);
for(i=;i<=m;i++)
{
scanf("%s %lf %s",s1,&d,s2);
u=Hash[s1];
v=Hash[s2];
dis[u][v]=max(dis[u][v],d);
}
floyd(n);
printf("Case %d: ",cas++);
for(i=;i<=n;i++)
if(dis[i][i]>1.0)
{
flag=;
break;
}
if(flag) printf("Yes\n");
else printf("No\n");
}
return ;
}

POJ 2240

(3)传递闭包

POJ 3660 Cow Contest

# include<cstdio>
# include<cstring>
# include<algorithm>
using namespace std; # define N
int f[N][N],beat[N],win[N]; void floyd(int n)
{
int i,j,k;
for(k=;k<=n;k++)
for(i=;i<=n;i++)
for(j=;j<=n;j++)
f[i][j]|=(f[i][k]&&f[k][j]);
} int main()
{
int i,j,n,m,u,v,ans;
while(scanf("%d%d",&n,&m)!=EOF)
{
ans=;
memset(beat,,sizeof(beat));
memset(win,,sizeof(win));
memset(f,,sizeof(f));
for(i=;i<=m;i++)
{
scanf("%d%d",&u,&v);
f[u][v]=;
}
floyd(n);
for(i=;i<=n;i++)
{
for(j=;j<=n;j++)
if(f[j][i]) //j beat i
{
win[j]++;
beat[i]++;
}
}
for(i=;i<=n;i++)
if(win[i]+beat[i]==n-)
ans++;
printf("%d\n",ans);
}
return ;
}

POJ 3660

(4)好题推荐(独立完成)

HDU 3631 Shortest Path    //深入理解floyd

# include<cstdio>
# include<cstring>
# include<algorithm>
using namespace std; # define INF <<
# define N int n,m,q;
int dis[N][N];
int mark[N]; void floyd(int k)
{
int i,j;
for(i=;i<n;i++)
for(j=;j<n;j++)
dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
} void init(int n)
{
int i,j;
memset(mark,,sizeof(mark));
for(i=;i<n;i++)
for(j=;j<n;j++)
dis[i][j]=(i==j)?:INF;
} int main()
{
//freopen("in.txt","r",stdin);
int i,j,u,v,w,op,cas=;
while(scanf("%d%d%d",&n,&m,&q)!=EOF&&(n+m+q))
{
init(n);
for(i=;i<=m;i++)
{
scanf("%d%d%d",&u,&v,&w);
dis[u][v]=min(dis[u][v],w);
}
if(cas>) printf("\n");
printf("Case %d:\n",cas++);
for(i=;i<=q;i++)
{
scanf("%d",&op);
if(op==)
{
scanf("%d",&u);
if(mark[u])
printf("ERROR! At point %d\n",u);
else
{
mark[u]=;
floyd(u);
}
}
else
{
scanf("%d%d",&u,&v);
if(!mark[u]||!mark[v])
printf("ERROR! At path %d to %d\n",u,v);
else if(dis[u][v]==INF)
printf("No such path\n");
else
printf("%d\n",dis[u][v]);
}
}
}
return ;
}

HDU 3631

HDU 4034 Graph               //深入理解floyd ,思维锻炼

# include<cstdio>
# include<cstring>
# include<algorithm>
using namespace std; # define N
int dis[N][N];
int vis[N][N]; int floyd(int n)
{
int i,j,k,ans=n*(n-);
memset(vis,,sizeof(vis));
for(k=;k<=n;k++)
for(i=;i<=n;i++)
for(j=;j<=n;j++)
{
if(dis[i][k]+dis[k][j]<dis[i][j])
return -;
if(!vis[i][j]&&i!=k&&j!=k&&i!=j&&dis[i][k]+dis[k][j]==dis[i][j])
{
ans--;
vis[i][j]=;
}
}
return ans;
} int main()
{
//freopen("in.txt","r",stdin);
int cas,T,i,j,n,ans;
scanf("%d",&T);
for(cas=;cas<=T;cas++)
{
scanf("%d",&n);
for(i=;i<=n;i++)
for(j=;j<=n;j++)
scanf("%d",&dis[i][j]);
printf("Case %d: ",cas);
ans=floyd(n);
if(ans==-)
printf("impossible\n");
else
printf("%d\n",ans);
}
return ;
}

HDU 4034

4. 个人总结

Floyd算法有很多其他的应用,需要不断的积累,但是我相信只要能理解好floyd的DP思想(每个k点插入或者不插入相关路径),很多问题多能迎刃而解.

附录:关于Floyd判断环的可行性

注:该附录未经严格验证,请读者认真思考 

[图论]Floyd 算法小结的更多相关文章

  1. floyd算法小结

    floyd算法是被大家熟知的最短路算法之一,利用动态规划的思想,f[i][j]记录i到j之间的最短距离,时间复杂度为O(n^3),虽然时间复杂度较高,但是由于可以处理其他相似的问题,有着广泛的应用,这 ...

  2. [图论]Dijkstra 算法小结

    Dijkstra 算法小结  By Wine93 2013.11 1. Dijkstra 算法相关介绍 算法阐述:Dijkstra是解决单源最短路径的算法,它可以在O(n^2)内计算出源点(s)到图中 ...

  3. 图论·Floyd算法·HDU2544&1874 (伪)2066

    在看到1874的题时,第一反应是用上一篇的并查集方法,后来查了一下是要用Floyd做,所以就去查Floyd算法的资料. 即插点法,是一种用于寻找给定的加权图中顶点间最短路径的算法. 核心代码:  ma ...

  4. 图论——Floyd算法拓展及其动规本质

    一.Floyd算法本质 首先,关于Floyd算法: Floyd-Warshall算法是一种在具有正或负边缘权重(但没有负周期)的加权图中找到最短路径的算法.算法的单个执行将找到所有顶点对之间的最短路径 ...

  5. 【uva 10048】Audiophobia(图论--Floyd算法)

    题意:有一个N点M边的无向带权图,边权表示路径上的噪声值.有Q个询问,输出 x,y 两点间的最大噪声值最小的路径的该值.(N≤100,M≤1000,Q≤10000) 解法:N值小,且问多对点之间的路径 ...

  6. 图论(floyd算法):NOI2007 社交网络

    [NOI2007] 社交网络 ★★   输入文件:network1.in   输出文件:network1.out   简单对比 时间限制:1 s   内存限制:128 MB [问题描述] 在社交网络( ...

  7. 图论之最短路径floyd算法

    Floyd算法是图论中经典的多源最短路径算法,即求任意两点之间的最短路径. 它可采用动态规划思想,因为它满足最优子结构性质,即最短路径序列的子序列也是最短路径. 举例说明最优子结构性质,上图中1号到5 ...

  8. 图论篇3——最短路径 Dijkstra算法、Floyd算法

    最短路径 问题背景:地图上有很多个城市,已知各城市之间距离(或者是所需时间,后面都用距离了),一般问题无外乎就是以下几个: 从某城市到其余所有城市的最短距离[单源最短路径] 所有城市之间相互的最短距离 ...

  9. 图论算法(二)最短路算法:Floyd算法!

    最短路算法(一) 最短路算法有三种形态:Floyd算法,Shortset Path Fast Algorithm(SPFA)算法,Dijkstra算法. 我个人打算分三次把这三个算法介绍完. (毕竟写 ...

随机推荐

  1. memcached 学习 1—— memcached+spring配置

    memcached 学习目录: memcached 学习 1—— memcached+spring配置 这几天自己搭建项目环境,解决问题如下: 有关常见的配置这里没有列出,中间遇到的搭建问题比较顺利g ...

  2. Testin

    http://www.testin.cn/ http://news.ccidnet.com/art/66/20150416/5815927_1.html 百度百科上面的   Testin是全球最大的移 ...

  3. hadoop2.0 和1.0的区别

    1. Hadoop 1.0中的资源管理方案Hadoop 1.0指的是版本为Apache Hadoop 0.20.x.1.x或者CDH3系列的Hadoop,内核主要由HDFS和MapReduce两个系统 ...

  4. C语言链表

    #include<stdio.h>#include<malloc.h>#include<stdlib.h> typedef struct Node{ int dat ...

  5. wordpress添加子主题

    使用子主题,可以继承父主题的所有功能,同时避免因为直接使用父主题在父主题升级时造成文件丢失的情况. 子主题的创建很简单: 1.首先在主题文件夹下(wp-content\themes)建立一个文件夹,用 ...

  6. 集群(cluster)原理(转)

      1.什么是集群 集群(cluster)就是一组计算机,他们作为整体向用户提供一组网络资源.这些单个的计算机系统就是集群的节点(node).一个理想的集群是,用户从不会意识到集群系统底层的节点,在他 ...

  7. [转载]Windows 7笔记本创建wifi热点供手机上网教程

    用智能手机的朋友会发现这样一个问题,智能手机比普通手机上网更耗流量.这是因为智能手机应用(软件)丰富,而且大部分应用都会自动联网.为此,许多人每月包了上百M的流量套餐,但用的时候还是小心翼翼,生怕流量 ...

  8. php中curl和fsockopen发送远程数据的应用

    最近要用到通过post上传文件,网上盛传的有curl的post提交和fsockopen,其中curl最简单,于是从最简单的说起. 这是简单的将一个变量post到另外一个页面 $url = ''; $d ...

  9. 常州培训 day3 解题报告

    第一题: 给出数轴正半轴上N个点的坐标和其权值,给出初始体力值M,人一开始在位置0,体力值会随着走过路程的增加而增加,走多少个单位的路消耗多少体力值.到每个点可以打掉,消耗的体力值就是其权值.求 最多 ...

  10. UVA 10970-Big Chocolate

    题目: 给你一块M*N的巧克力,问把它切成最小单元需要最少切几刀,分开的就不能一起切了. 分析: 每次切割只能多产生一个部分,分成M*N个部分,必然要切M*N-1刀. 一个长为m宽为n的长方形和m*n ...