Luogu P2872 [USACO07DEC] Building Roads S (minimum spanning tree prim)

Title Portal

The prim algorithm is introduced here.
Prim algorithm is also an algorithm of minimum spanning tree. For a graph, we have to build its minimum spanning tree. We have written a kruskal algorithm for sparse graphs before. Now we introduce the prim algorithm for dense graphs.

The time complexity of kruskal is eloge (e is the number of edges), the time complexity of prim naive version is O (n ^ 2), the time complexity after optimization of the small root heap is elogn, (n is the number of vertices), for graphs with many edges , Prim is obviously faster.

We set a set of two points, U and V. U represents points already in the spanning tree, and V represents points that are not in the spanning tree. We start at any point, such as point 1. Every time we find a point closest to any point in the spanning tree, and then add it to the spanning tree, and relax the points connected to it until all the remaining n-1 points are added to the spanning tree.

Naive version of prim algorithm code:

#include<bits/stdc++.h>
using namespace std;
const int N=1e3+5;
const int inf=0x7fffffff;
const int mod=1e9+7;
const int eps=1e-6;
typedef long long ll;
typedef unsigned long long ull;
#define ls p<<1
#define rs p<<1|1
#define fi first
#define se second
#define mp make_pair
#define pb push_back
#define pii pair<int,int>
#define int long long
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define endl '\n'
int x[N],y[N];
double js(int x1,int x2,int y1,int y2)
{
    return sqrt(pow(double(x1-x2),2)+pow(double(y1-y2),2));//这个地方必须强制double,也可以有其他写法,要不有四个点会输出-nan
}
double a[N][N],d[N];
int b[N];
signed main()
{
    IOS;
    int n,m;
    cin>>n>>m;
    for(int i=1;i<=n;i++)
    {
        cin>>x[i]>>y[i];
    }
    for(int i=1;i<=n;i++)
    {
        for(int j=i+1;j<=n;j++)
        {
            a[i][j]=a[j][i]=js(x[i],x[j],y[i],y[j]);
        }
    }
    for(int i=1;i<=m;i++)
    {
        int q,p;
        cin>>p>>q;
        a[p][q]=a[q][p]=0;
    }
    memset(d,0x7f,sizeof d);
    for(int i=1;i<=n;i++)
    {
        d[i]=a[1][i];
    }
    d[1]=0;b[1]=1;
    for(int i=1;i<=n-1;i++)
    {
        int k=0;
        for(int j=1;j<=n;j++)
        {
            if(!b[j]&&d[j]<d[k])
            {
                k=j;
            }
        }
        b[k]=1;
        for(int j=1;j<=n;j++)
        {
            if(!b[j]&&a[j][k]<d[j])
                d[j]=a[j][k];
        }
    }
    double res=0;
    for(int i=1;i<=n;i++)
    {
        res+=d[i];
    }
    printf("%.2f",res);
}

We found that every time we add a point, we have to update the information O (n), which is a waste of time. In fact, when updating, we only need to update the point connected to the newly added point. The chain forward star can sacrifice space for time to meet this requirement.

Chained forward star + small root heap optimized version

#include<bits/stdc++.h>
using namespace std;
const int N=1e3+5;
const int inf=0x7fffffff;
const int mod=1e9+7;
const int eps=1e-6;
typedef long long ll;
typedef unsigned long long ull;
#define ls p<<1
#define rs p<<1|1
#define fi first
#define se second
#define mp make_pair
#define pb push_back
#define pii pair<int,int>
#define int long long
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define endl '\n'
int x[N],y[N];
double js(int x1,int x2,int y1,int y2)
{
    return sqrt(pow(double(x1-x2),2)+pow(double(y1-y2),2));
}
int head[1100005],nxt[1100005],to[1100005];double val[1100005];int tot=0;
void add(int u,int v,double w)
{
    nxt[++tot]=head[u];
    to[tot]=v;
    val[tot]=w;
    head[u]=tot;
}
int b[N];int n,m;
void prim()
{
    priority_queue<pair<double,int> >q;
    q.push(mp(0,1));
    int cnt=0;double res=0;
    while(!q.empty())
    {
        int u=q.top().se;
        double di=q.top().fi;
        q.pop();
        if(!b[u])
        {
            b[u]=1;
            res+=di;
            for(int i=head[u];i;i=nxt[i])
            {
                int v=to[i];
                if(!b[v])
                {
                    q.push(mp(-val[i],v));
                }
            }
        }
    }
    printf("%.2f",-res);
}
signed main()
{
    IOS;
    cin>>n>>m;
    for(int i=1;i<=n;i++)
    {
        cin>>x[i]>>y[i];
    }
    for(int i=1;i<=n;i++)
    {
        for(int j=i+1;j<=n;j++)
        {
            add(i,j,js(x[i],x[j],y[i],y[j]));
            add(j,i,js(x[i],x[j],y[i],y[j]));
        }
    }
    for(int i=1;i<=m;i++)
    {
        int l,r;
        cin>>l>>r;
        add(l,r,0);add(r,l,0);
    }
    prim();
}

Published 93 original articles · won praise 9 · views 4203

Guess you like

Origin blog.csdn.net/Joker_He/article/details/105183403