当前位置:   article > 正文

图论——最短路算法_图论算最短距离倒数时

图论算最短距离倒数时

 引入:

如上图,已知图G。

问节点1到节点3的最短距离。

可心算而出为d[1,2]+d[2,3]=1+1=2,比d[1,3]要小。

求最短路径算法:

1.Floyd(弗洛伊德)

是一种基于三角形不等式的多源最短路径算法。边权可以为负数

表现为a[i,j]+a[j,k]<a[i,k]。

算法思想:

枚举“中转站”(k),“起点”(i),“终点”(j)

设d[i,j]为由i点到j点的最短路径

则 d[i,j]=min(d[i,j],d[i,k]+d[k,j])

初始化d[i,j]为无穷大 (1\leq i\leq n,1\leq j\leq n

算法模板如下:
 

  1. inline int Floyd(int n,int st,int ed)// n个点,起点st,终点ed,返回st到ed的最短距离
  2. {
  3. int d[n][n];
  4. memset(d,0x3f,sizeof(d));
  5. for(int i=1;i<=n;i++) d[i][i]=0;
  6. for(int k=1;k<=n;k++)
  7. {
  8. for(int i=1;i<=n;i++)
  9. {
  10. for(int j=1;j<=n;j++)
  11. {
  12. d[i][j]=min(d[i][j],d[i][k]+d[k][j]);
  13. }
  14. }
  15. }
  16. return d[st][ed];
  17. }

 补充:Floyd输出最短路径。

题目:有向图中任意两点最短路径(floyd)
题目描述

  一个含n个结点的有向图(注意:是有向图!!),以矩阵存储方式给出,请求出指定的多组两个点之间的最短距离及其最短路径。

输入输出格式
输入格式:

  第1行,一个整数n(0 < n < 300 ),表示有向图中结点的个数。
  第2行到第(n+1)行,是一个n*n的矩阵,表示无向图中各结点之间的联结情况,矩阵中的数据为小于1000的正整数,其中 -1 表示无穷大!!
  第(n+2)行,一个整数m,表示接下来有m组顶点 < i , j >对 ,其中,i是起点,j是终点,且i不等于j。
  接下来有m行,每行两个整数,中间一个空格间隔,分别表示i和j,表示求解i点到j点的最短距离及最短路径。

  注:输入数据已经确保答案每一组顶点间的最短路径是唯一的,无多解数据存在,顶点编号用数字表示,从1开始编号,至n结束!

输出格式:

  共 2m 行。
  第(m-1)*2+1行,一个整数,表示第m组顶点的最短距离,若两点间距离为无穷大,则输出 -1。
  第(m-1)*2+2行,用顶点编号表示的路径序列,各顶点编号间用一个空格间隔,表示第m组顶点的最短路径,若两点间距离为无穷大,则输出的路径序列为 -1。

输入输出样例
输入样例#1:

3
0 4 11
6 0 2
3 -1 0
2
2 1
3 2 

输出样例#1:

5
2 3 1
7
3 1 2

代码如下:
 

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. int n,q;
  4. int d[10001][10001],pre[10001][10001];
  5. void dg(int i,int j)
  6. {
  7. if(i==j||pre[i][j]==0) return;
  8. int k=pre[i][j];
  9. dg(i,k);
  10. dg(k,j);
  11. }
  12. int main()
  13. {
  14. cin>>n;
  15. for(int i=1;i<=n;i++)
  16. {
  17. for(int j=1;j<=n;j++)
  18. {
  19. cin>>d[i][j];
  20. if(d[i][j]==-1)
  21. {
  22. d[i][j]=0x7fffff;
  23. }
  24. }
  25. }
  26. for(int k=1;k<=n;k++)
  27. {
  28. for(int i=1;i<=n;i++)
  29. {
  30. for(int j=1;j<=n;j++)
  31. {
  32. if(d[i][k]+d[k][j]<d[i][j])
  33. {
  34. d[i][j]=d[i][k]+d[k][j];
  35. pre[i][j]=k;
  36. }
  37. }
  38. }
  39. }
  40. cin>>q;
  41. for(int i=1;i<=q;i++)
  42. {
  43. int x,y;
  44. cin>>x>>y;
  45. cout<<d[x][y]<<endl;
  46. cout<<x<<" ";
  47. dg(x,y);
  48. cout<<y;
  49. cout<<endl;
  50. }
  51. return 0;
  52. }

传递闭包(连通性)

d[i,j]=d[i,j]|(d[i,k]&d[k,j])
d[i,j]表示i与j是否连通。

题目:刻录光盘

题目描述

  在FJOI2010夏令营快要结束的时候,很多营员提出来要把整个夏令营期间的资料刻录成一张光盘给大家,以便大家回去后继续学习。组委会觉得这个主意不错!可是组委会一时没有足够的空光盘,没法保证每个人都能拿到刻录上资料的光盘,怎么办呢?!

  DYJ分析了一下所有营员的地域关系,发现有些营员是一个城市的,其实他们只需要一张就可以了,因为一个人拿到光盘后,其他人可以带着U盘之类的东西去拷贝啊!

  他们愿意某一些人到他那儿拷贝资料,当然也可能不愿意让另外一些人到他那儿拷贝资料,这与我们FJOI宣扬的团队合作精神格格不入!!!

  现在假设总共有N个营员(2<=N<=200),每个营员的编号为1~N。DYJ给每个人发了一张调查表,让每个营员填上自己愿意让哪些人到他那儿拷贝资料。当然,如果A愿意把资料拷贝给B,而B又愿意把资料拷贝给C,则一旦A获得了资料,则B,C都会获得资料。

  现在,请你编写一个程序,根据回收上来的调查表,帮助DYJ计算出组委会至少要刻录多少张光盘,才能保证所有营员回去后都能得到夏令营资料?

输入输出格式
输入格式:

先是一个数N,接下来的N行,分别表示各个营员愿意把自己获得的资料拷贝给其他哪些营员。即输入数据的第i+1行表示第i个营员愿意把资料拷贝给那些营员的编号,以一个0结束。如果一个营员不愿意拷贝资料给任何人,则相应的行只有1个0,一行中的若干数之间用一个空格隔开。

输出格式:

一个正整数,表示最少要刻录的光盘数。

输入输出样例
输入样例#1:

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

输出样例#1:

1

代码:
  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. int f[100001],d[300][300],g[100001],ans;
  4. int main()
  5. {
  6. int n;
  7. cin>>n;
  8. memset(d,0x3f,sizeof(d));
  9. for(int i=1;i<=n;i++)
  10. {
  11. f[i]=i;
  12. }
  13. for(int i=1;i<=n;i++)
  14. {
  15. int x;
  16. while(1)
  17. {
  18. cin>>x;
  19. if(x==0) break;
  20. d[i][x]=1;
  21. }
  22. }
  23. for(int k=1;k<=n;k++)
  24. {
  25. for(int i=1;i<=n;i++)
  26. {
  27. for(int j=1;j<=n;j++)
  28. {
  29. if(i!=j&&j!=k&&k!=i)
  30. {
  31. if(d[i][k]==1&&d[k][j]==1)
  32. {
  33. d[i][j]=1;
  34. }
  35. }
  36. }
  37. }
  38. }
  39. for(int i=1;i<=n;i++)
  40. {
  41. for(int j=1;j<=n;j++)
  42. {
  43. if(d[i][j]==1)
  44. {
  45. f[j]=f[i];
  46. }
  47. }
  48. }
  49. for(int i=1;i<=n;i++)
  50. {
  51. if(f[i]==i)
  52. {
  53. ans++;
  54. }
  55. }
  56. cout<<ans;
  57. return 0;
  58. }

2.dijkstra(狄克斯特拉,迪杰斯特拉)

基于贪心的单源最短路径算法。边权必须为正数

基本思想:

设d[i]为起点s到终点i的最短路径,a[i,j]为点i到点j边权。

1.找  min\begin{Bmatrix} d[i] \end{Bmatrix}\left ( 1\leqslant i\leqslant n ,vis[i]=true \right ),并将其用k记录

2.vis[k]=true

3.d[i]=min\begin{Bmatrix} d[i],d[k]+a[k][i] \end{Bmatrix}\left ( 1\leqslant i\leqslant n \right ) 松弛操作,用k来更新图中所有点。

  1. int dijkstra(int n,int st,int ed)
  2. {
  3. int dis[n+1],vis[n+1];
  4. memset(dis,0x3f,sizeof(dis));
  5. memset(vis,0,sizeof(vis));
  6. dis[st]=0;
  7. for(int i=1;i<=n;i++)
  8. {
  9. int k,minn=0x7fffff;
  10. for(int j=1;j<=n;j++)if(!vis[j]&&dis[j]<minn) minn=dis[j],k=j;
  11. vis[k]=true;
  12. for(int j=1;j<=n;j++) d[j]=min(d[j],d[k]+a[k][j]);
  13. }
  14. return d[ed];
  15. }

堆优化dijkstra:
 

  1. typedef pair<int,int> P;
  2. struct node{
  3. int to;
  4. int next;
  5. int w;
  6. }edge[10000010];
  7. int head[10000010],d[10000010];
  8. int cnt;
  9. int n,m,x,y,z,s;
  10. void add_edge(int u,int v,int w)
  11. {
  12. edge[cnt].to=v;
  13. edge[cnt].w=w;
  14. edge[cnt].next=head[u];
  15. head[u]=cnt++;
  16. }
  17. void dijkstra(int s)
  18. {
  19. priority_queue< P,vector<P>,greater<P> >q;
  20. memset(d,0x3f,sizeof(d));
  21. d[s]=0;
  22. q.push(P(0,s));
  23. while(!q.empty())
  24. {
  25. P p=q.top();
  26. q.pop();
  27. int u=p.second;
  28. if(d[u]<p.first) continue;
  29. for(int i=head[u];i!=-1;i=edge[i].next)
  30. {
  31. int v=edge[i].to;
  32. if(d[v]>d[u]+edge[i].w)
  33. {
  34. d[v]=d[u]+edge[i].w;
  35. q.push(P(d[v],v));
  36. }
  37. }
  38. }
  39. }

3.Bellman-Ford

O(n*m) 但有更优的,由其转换而来的Spfa算法,不再赘述。边权可以为负数

4.Spfa

基于bellman-Ford,用队列优化的单源最短路径算法,边权可以为负数,可用于判断负环。

代码如下:

  1. int head=0,tail=1;
  2. team[1]=s,vis[s]=1,dis[s]=0;
  3. while(head<tail)
  4. {
  5. head=(head+1)%10000;
  6. int u=team[head];
  7. vis[u]=0;
  8. for(int i=1;i<=len[u];i++)
  9. {
  10. int v=le[u][i];
  11. if(dis[v]>dis[u]+a[u][v])
  12. {
  13. dis[v]=dis[u]+a[u][v];
  14. if(vis[v]==0)
  15. {
  16. tail=(tail+1)%10000;
  17. team[tail]=v;
  18. vis[v]=1;
  19. }
  20. }
  21. }
  22. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/IT小白/article/detail/243696
推荐阅读
相关标签
  

闽ICP备14008679号