注:此博客以
P3371 【模板】单源最短路径(弱化版) - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)https://www.luogu.com.cn/problem/P3371P4779 【模板】单源最短路径(标准版) - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
https://www.luogu.com.cn/problem/P4779为图的遍历的例题进行讲解;
以
P3366 【模板】最小生成树 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)https://www.luogu.com.cn/problem/P3366为图的最小生成树的例题进行讲解。
1.spfa遍历
spfa遍历可以说就是图论版的稍微更改一些地方的bfs,具体算法如下:
现在有一幅无向图,设起点为1,如下:
从1开始,可遍历到2,6,5,3,4,长度分别为5,3,6,3,4;
再从2开始,可遍历到6,(因为1是上一个点,所以距离相等,没有再次遍历的必要),长度为6(5+1),没有之前的优,所以不更新。
再从6开始,可遍历到5,(不计1号点和2号点,原因同上),长度为5(q取8和5中的最小值),比之前的方案(l路程为6的)优,所以更新。
用以上的逐个方法更新一遍,即为spfa遍历算法。
具体代码如下:
#include
using namespace std;
const int N=10001,M=1000001;
long long n,m,s,dis[N],q[M],h=0,t=-1;
struct node{
int to,dist;
}u;
vectora[N];
bool use[N];
void spfa(){
dis[s]=0;
q[++t]=s;
use[s]=true;
while(h<=t){
int v=q[h++];
use[v]=0;
for(int i=0;i
2.dijkstra遍历
我们发现spfa算法只适用于稀疏图,用它在遍历比较密集的图就不太合适了,这可怎么办呢?dijkstra算法来了!
还是这幅图,但是我们这次以3为起点,我们发现:3到达6个点的距离分别是3,-1,0,2,4,-1(-1表示无法到达),我们发现:这个点到其它点(不包括它自己)的距离的最小值是2,也就是从3到4这条路,所以从起点出发到4号点的最优值就是2,此点遍历结束,换4号点。
从4号点,只能去1号点,而去一号点距离为5,没之前的优,不更新。
用以上的逐个方法更新一遍,即为dijkstra遍历算法。
具体代码如下:
#include
using namespace std;
int n,m,st,dis[100001];
bool use[10001];
struct node{
int to,v;
};
vectora[500001];
int find(){
int mn=0xffffffe,k=-1;
for(int i=1;i<=n;i++)if(dis[i]!=-1&&!use[i]&&dis[i]
但是以上两种方法虽然提交P3371 【模板】单源最短路径(弱化版) - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)https://www.luogu.com.cn/problem/P3371可以AC,但是如果拿以上两行代码去提交
P4779 【模板】单源最短路径(标准版) - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)https://www.luogu.com.cn/problem/P4779是必然TLE的,那怎么办呢?
该STL(优先队列)版dijkstra出场了!!
代码如下:
#include
#include
#include
using namespace std;
const int N=100001;
struct in{
int to,v;
};
struct node{
int id,sum;
node(int x,int y):id(x),sum(y){};
friend bool operator<(const node &a,const node &b){return a.sum>b.sum;}
};
vectora[N];
priority_queueq;
int n,m,s,dis[N];
bool use[N];
void dijkstral(){
for(int i=1;i<=n;i++)dis[i]=0x3fffffff;//2147483647
dis[s]=0;
q.push(node(s,0));
memset(use,false,sizeof(use));
while(!q.empty()){
node u=q.top();
q.pop();
int k=u.id;
if(use[k])continue;
use[k]=true;
for(int i=0,x;i
使用并查集 and BFS进行搜索,代码如下:
prim搜索
比较像dijkstra,要注意的是,我们现在要选的是最短的边,所以不需要累加,具体代码如下:
#include
using namespace std;
const int N=5001,M=1e6+1;
struct edge{
int to,nextt,w;
}a[M];
struct Node{
int id,len;
bool operator<(const Node &b)const{return len>b.len;}
};
int n,m,head[N],num,dis[N];
bool sign[N];
void Prim(int st){
priority_queuepq;
memset(sign,false,sizeof(sign));
memset(dis,0x3f,sizeof(dis));
pq.push((Node){st,0});
dis[st]=0;
int ans=0;
while(!pq.empty()){
int u=pq.top().id;
pq.pop();
if(sign[u])continue;
sign[u]=true;
ans+=dis[u];
for(int i=head[u];i>0;i=a[i].nextt)if(!sign[a[i].to]&&dis[a[i].to]>a[i].w)dis[a[i].to]=a[i].w,pq.push((Node){a[i].to,dis[a[i].to]});
}
for(int i=1;i<=n;i++)if(!sign[i]){
printf("orz");
return;
}
printf("%d",ans);
return;
}
int main(){
scanf("%d %d",&n,&m);
for(int i=1,x,y,z;i<=m;i++)scanf("%d %d %d",&x,&y,&z),a[++num].to=y,a[num].nextt=head[x],a[num].w=z,head[x]=num,a[++num].to=x,a[num].nextt=head[y],a[num].w=z,head[y]=num;
Prim(1);
return 0;
}
都看到这里了,给个赞再走呗?