Luogu P2872 [USACO07DEC] Construcción de carreteras S (primo de árbol de expansión mínimo)

Portal de títulos

El algoritmo prim se presenta aquí.
El algoritmo Prim también es un algoritmo de árbol de expansión mínima. Para un gráfico, tenemos que construir su árbol de expansión mínima. Hemos escrito un algoritmo kruskal para gráficos dispersos antes. Ahora presentamos el algoritmo prim para gráficos densos.

La complejidad temporal de kruskal es eloge (e es el número de aristas), la complejidad temporal de la versión primitiva ingenua es O (n ^ 2), y la complejidad temporal del montón de raíces pequeñas optimizado es elogn, (n es el número de vértices) , Prim es obviamente más rápido.

Establecemos un conjunto de dos puntos, U y V. U representa puntos que ya están en el árbol de expansión y V representa puntos que no están en el árbol de expansión. Comenzamos en cualquier punto, como el punto 1. Cada vez que encontramos un punto más cercano a cualquier punto en el árbol de expansión, y luego lo agregamos al árbol de expansión, y relajamos los puntos conectados a él, hasta que todos los puntos n-1 restantes se agreguen al árbol de expansión.

Versión ingenua del código del algoritmo prim:

#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);
}

Descubrimos que cada vez que agregamos un punto, tenemos que actualizar la información O (n), lo cual es una pérdida de tiempo. De hecho, al actualizar, solo necesitamos actualizar el punto conectado al punto recién agregado. La cadena de estrellas hacia adelante puede sacrificar espacio por tiempo para cumplir con este requisito.

Versión optimizada encadenada estrella + montón dinámico de raíz pequeña

#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();
}

Publicado 93 artículos originales · ganado elogios 9 · vistas 4203

Supongo que te gusta

Origin blog.csdn.net/Joker_He/article/details/105183403
Recomendado
Clasificación