浅论3大方法求单源最短路以及2大方法求最小生成树
来源:互联网 发布:房屋外观设计简单软件 编辑:程序博客网 时间:2024/05/17 06:10
- Prim法求最小生成树
- Kruskal法求最小生成树
- Dijkstra法求单源最短路
- Floyed法求单源最短路
- Bellman_Ford or SPFA 求单源最短路
在打比赛之前要打好基础.这一次我搞了一些单源最短路以及最小生成树的代码.我把它们放在这里.
Prim法求最小生成树
首先我们手上有一个加权连通图,这种我们可以自己脑补.
我建立一个集合E表示已经加入生成树的点.
然后我们随意选择一个点d,让其加入E,并扫描与它相邻的所有点v,找出最小的一条边并将此边所连的v加入E.然后把d更新为v.不断如此做直到E=V(V即我们一开始拿到的图的所有点组成的集合为止).这里用堆进行优化,复杂度O(nlogn).我的代码可能比较骚.大家看看就好.
#include<bits/stdc++.h>#define pii pair<int,int>using namespace std;const int boss=1e5;vector<pii> r[boss+10];bool vis[boss+10];priority_queue<pii,vector<pii>,greater<pii> > q;int main(){int n,m,u,v,c,i,answer=0;for (scanf("%d%d",&n,&m),i=1;i<=m;i++) scanf("%d%d%d",&u,&v,&c),r[u].push_back((pii){c,v}),r[v].push_back((pii){c,u});for (int now=1;--n;answer+=q.top().first,now=q.top().second,q.pop()) { for (vis[now]=1,i=0;i<r[now].size();i++) if (!vis[r[now][i].second]) q.push(r[now][i]); while (vis[q.top().second]) q.pop(); }printf("%d",answer);}
Kruskal法求最小生成树
我建议写这个,这个写起来简单很多,不需要过多考虑.
首先对边的权值从小到大排序,然后按顺序选择最小边,只要该边所连接的两点不是已经在生成树上了,就可以添加之.至于判断两点是不是在树上,用并查集就可以了.复杂度也是O(nlogn),但好写多了.因为题目中ans会爆int,我define int long long.
#include<bits/stdc++.h>#define int long longusing namespace std;const int boss=1e5;struct edge{int from,to,cost;}bian[boss*2+10];bool cmp(edge a,edge b){return a.cost<b.cost;}int fa[boss+10],n,m;int find(int x){return x==fa[x]?x:(fa[x]=find(fa[x]));}main(){int i,answer=0;for (scanf("%lld%lld",&n,&m),i=1;i<=m;i++) scanf("%lld%lld%lld",&bian[i].from,&bian[i].to,&bian[i].cost);for (sort(bian+1,bian+m+1,cmp),i=1;i<=n;i++) fa[i]=i;for (int cnt=1,p=1;cnt<n&&p<=m;p++) { int u=find(bian[p].from),v=find(bian[p].to); if (u==v) continue; fa[u]=v,cnt++,answer+=bian[p].cost; }printf("%lld",answer);}
Dijkstra法求单源最短路
老师非常毒,要我们输出路径.当然路径什么的不算啥啦,只要用一个pre数组存储到t这个点往回经过的点,然后递归一下就可以了.
至于方法,当然是把dist数组初始化为inf,再定义E为已经选取的点的集合,然后选取开始点d,搜索与其相邻的所有点,将所有点的距离更新成其与d的距离.把d更新为v,然后再次搜索,如果有dist[i]>dist[v]+dist[v][i],则我们就用后者更新前者,以此类推扫过所有点,直到E=V.
#include<bits/stdc++.h>using namespace std;const int inf=0x3f3f3f3f;int s,t,m,n,pre[1010],edge[1010][1010],dist[1010];bool used[1010];void dijkstra(int s){int i,v=0;for (memset(dist,inf,sizeof dist),memset(pre,-1,sizeof pre),dist[s]=0;v!=-1;) { for (v=-1,i=1;i<=n;i++) if (!used[i]&&(v==-1||dist[i]<dist[v])) v=i; if (v!=-1) for (used[v]=true,i=1;i<=n;i++) if (dist[i]>dist[v]+edge[v][i]) { dist[i]=dist[v]+edge[v][i]; pre[i]=v; } }}vector<int> get_lujing(int t){vector<int> lu;for (;t!=-1;t=pre[t]) lu.push_back(t);reverse(lu.begin(),lu.end());return lu;}int main(){int i;memset(edge,inf,sizeof edge);scanf("%d%d%d%d",&s,&t,&n,&m);for (i=1;i<=m;i++) { int u,v,c; scanf("%d%d%d",&u,&v,&c); edge[u][v]=c,edge[v][u]=c; }dijkstra(s);printf("%d\n",dist[t]);vector<int> lujing=get_lujing(t);for (i=0;i<lujing.size();i++) printf("%d ",lujing[i]);}
Floyed法求单源最短路
这个代码虽然是O(n^3)的,但是写起来简单,只要一行.核心代码与矩阵乘法相似.
if (edge[i][j]>edge[i][k]+edge[k][j]) edge[i][j]=edge[i][k]+edge[k][j]
Perfect.这里要输出路径,用一个二维数组pre存储,递归输出路径.具体观看代码.
#include<bits/stdc++.h>using namespace std;typedef long long ll;const ll inf=12345678987654321;ll edge[210][210],n,m,pre[210][210];void get_path(ll s,ll t){if (s==t) printf("%lld",t);else { printf("%lld ",s); get_path(pre[t][s],t); }}int main(){ll s1,t1,s2,t2,i,j,k;scanf("%lld%lld%lld%lld%lld%lld",&s1,&t1,&s2,&t2,&n,&m);memset(edge,63,sizeof edge);memset(pre,-1,sizeof pre);for (i=1;i<=n;i++) pre[i][i]=i;for (i=1;i<=m;i++) { ll u,v,c; scanf("%lld%lld%lld",&u,&v,&c); edge[v][u]=edge[u][v]=min(edge[u][v],c); pre[u][v]=u,pre[v][u]=v; }for (k=1;k<=n;k++) for (i=1;i<=n;i++) for (j=1;j<=n;j++) if (edge[i][j]>edge[i][k]+edge[k][j]) edge[i][j]=edge[i][k]+edge[k][j],pre[i][j]=pre[k][j];else if (edge[i][k]+edge[k][j]==edge[i][j]&&i!=k&&j!=k) pre[i][j]=min(pre[i][j],pre[k][j]);printf("%lld\n",edge[s1][t1]);get_path(s1,t1);printf("\n%lld\n",edge[s2][t2]);get_path(s2,t2);}
Bellman_Ford or SPFA 求单源最短路
这个方法比起上面两个来优点就是可以判负环,如果在更新n-1次之后还能继续更新,就说明此图没有最短路.具体参见代码.
#include<bits/stdc++.h>using namespace std;const int boss=1e5;struct edge{int from,to,cost;}bian[boss*2+10];stack<int> final;int n,m,s,t,pre[boss+10],dist[boss+10];bool nico;void bellman_ford(int s){int i,k;memset(dist,63,sizeof dist);dist[s]=0;for (k=1;k<n;k++) { bool judge=0;//这里更好的变量名是update,判断有没有更新过. for (i=1;i<=m;i++) if (dist[bian[i].to]>dist[bian[i].from]+bian[i].cost) { dist[bian[i].to]=dist[bian[i].from]+bian[i].cost; pre[bian[i].to]=bian[i].from; judge=1; } if (!judge) break; }for (nico=0,i=1;i<=m;i++) if (dist[bian[i].to]>dist[bian[i].from]+bian[i].cost) nico=1;}vector<int> get_lujing(int t){vector<int> lu;for (;t!=pre[t];t=pre[t]) lu.push_back(t);reverse(lu.begin(),lu.end());return lu;}int main(){int i;scanf("%d%d%d%d",&s,&t,&n,&m);for (i=1;i<=n;i++) pre[i]=i;for (i=1;i<=m;i++) scanf("%d%d%d",&bian[i].from,&bian[i].to,&bian[i].cost);bellman_ford(s);if (nico) return printf("You show me the wrong map!");printf("%d\n",dist[t]);vector<int> lujing=get_lujing(t);for (printf("%d ",s),i=0;i<lujing.size();i++) printf("%d ",lujing[i]);}
好,我就说到这里,谢谢大家的观看.
- 浅论3大方法求单源最短路以及2大方法求最小生成树
- 最小生成树大汇总
- 【各大OJ】最小生成树专题
- 【复习记录】最小/大生成树
- 求大整数的阶乘的方法
- poj 3662 二分+最短路,求第k大最小权值
- 贪心方法:最小生成树
- 最小生成树Prim方法
- 密码学—如何随机生成大素数以及Miller Rabin素性检测方法
- 最短路(最小生成树)
- 武大oj 1566 Spanning Tree(最小生成树)
- 【★】最小生成树的两大解法!
- 网络传输大文件优化方法(求补充)
- scala 对大数据量排序求中位数 lookup方法
- 求一个数组中第k大的数方法
- 求一个数组中第k大的数方法
- 最小生成树与最短路径的区别以及实现方法
- 最小生成树与最短路径的区别以及实现方法
- 链表的简单操作
- [HDU]4507 恨7不成妻 数位Dp好题
- BZOJ 1596: [Usaco2008 Jan]电话网络 树形dp||贪心
- Windows 下 Apache2 Django配置(针对找不到mod_wsgi.so)
- NetDataUtil_获取网络数据的工具类
- 浅论3大方法求单源最短路以及2大方法求最小生成树
- 记忆网络之Hierarchical Memory Networks(架构分层)
- U盘启动盘恢复原来的大小
- Python黑帽子学习笔记-----第三章
- win7系统在启动MySQL Query Browser时出现的Error2003错误及解决办法
- p59 第一题
- linux常见网络设置
- NetWorkUtil_使用网络状态的判断
- webpack安装和命令行