图的遍历和最小生成树

注:此博客以​

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张图片

从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算法来了!

图的遍历和最小生成树_第2张图片

还是这幅图,但是我们这次以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;
}

都看到这里了,给个赞再走呗?

你可能感兴趣的:(笔记,图论,算法)