省赛复习 最小生成树专题

Posted 钟钟终

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了省赛复习 最小生成树专题相关的知识,希望对你有一定的参考价值。

P8074 [COCI2009-2010#7] SVEMIR
要求出min|x_A-x_B|,|y_A-y_B|,|z_A-z_B|,数量级为1e5,若是两两相连,等差数列为n*(n-1)/2肯定会MLE,超出内存。
因此,注意边长间的关系。当两个点x距离很近时,表达式得到的值最小,同理y,z也是。因此会想到排三次序,每次排序连接相邻的两个点,数量级为最大为3e5.
kruskral算法的复杂度O(e*loge),
prim算法的复杂度为O(n*n),可脱离边。
prim算法复杂度为O(n*loge),还是无法脱离边
因此,kruskral算法对于稀疏图最佳,prim算法用于稠密图最佳。

#include <bits/stdc++.h>
#define endl '\\n'
#define ll long long
#define pb push_back
using namespace std;
const int N=5e5+5;
int n,f[N],cnt,ans;
struct node

    int x,y,z,id;
e[N];
bool cmp1(node e1,node e2)   return e1.x<e2.x;
bool cmp2(node e1,node e2)   return e1.y<e2.y;
bool cmp3(node e1,node e2)   return e1.z<e2.z;
struct edge

    int u,v,w;
p[N];
void add(int i,int j,int w)

    p[++cnt].u=i,p[cnt].v=j,p[cnt].w=w;

bool cmp4(edge p1,edge p2)  return p1.w<p2.w;
int r_find(int r)

    if(f[r]==r)
        return f[r];
    f[r]=r_find(f[r]);
    return f[r];

void kruskral()

    for(int i=1;i<=n;i++)
        f[i]=i;
    int res=0;
    for(int i=1;i<=cnt;i++)
    
        //cout<<p[i].w<<endl;
        int fx=r_find(p[i].u),fy=r_find(p[i].v);
        if(fx!=fy)
        
            f[fx]=fy;
            ans+=p[i].w;res+=1;
            if(res==n-1)
                break;
        
    

signed main()

    cin>>n;
    for(int i=1;i<=n;i++)
        cin>>e[i].x>>e[i].y>>e[i].z,e[i].id=i;

    sort(e+1,e+n+1,cmp1);
    for(int i=1;i<n;i++)
        add(e[i].id,e[i+1].id,e[i+1].x-e[i].x);

    sort(e+1,e+n+1,cmp2);
    for(int i=1;i<n;i++)
        add(e[i].id,e[i+1].id,e[i+1].y-e[i].y);

    sort(e+1,e+n+1,cmp3);
    for(int i=1;i<n;i++)
        add(e[i].id,e[i+1].id,e[i+1].z-e[i].z);

    sort(p+1,p+cnt+1,cmp4);
    kruskral();
    cout<<ans<<endl;
    return 0;


Prim算法流程:

1.开始将起点(本题随意)标记为蓝点;
2.找一条连接蓝点集合中一点和白点集合中一点最短的边;
3.将该边连接的白点加入蓝点;
4.将该新加入的蓝点所有连接的白点最短边更新;
5.返回第二步,直到n个点都被选入最小生成树为止。

P1265 公路修建

浮点数要写出0x7f !!!

#include <bits/stdc++.h>
#define endl '\\n'
#define ll long long
#define pb push_back
using namespace std;
const int N=1e5+5;
const double inf=1e9;
int n;
double x[5005],y[5005],dis[5005],ans;
bool vis[5005];

signed main()

    ios::sync_with_stdio(false);
    cin.tie(0);
    cin>>n;
    for(int i=1;i<=n;i++)
        cin>>x[i]>>y[i];
    memset(dis,inf,sizeof dis);
    dis[1]=0;
    for(int i=1;i<=n;i++)
    
        int k=0;
        for(int j=1;j<=n;j++)  //找到一个距离最小的加入到蓝点
            if(!vis[j]&&dis[j]<dis[k])
                k=j;
        vis[k]=1;
        for(int j=1;j<=n;j++) //将该蓝点连接的所有白点更新
        
            double tmp=(x[k]-x[j])*(x[k]-x[j])+(y[k]-y[j])*(y[k]-y[j]);
            if(!vis[j]&&tmp<dis[j])
                dis[j]=tmp;
        
    
    for(int i=1;i<=n;i++)
        ans+=sqrt(dis[i]);
    cout<<fixed<<setprecision(2)<<ans<<endl;
    return 0;


以上是关于省赛复习 最小生成树专题的主要内容,如果未能解决你的问题,请参考以下文章

最小生成树专题

图论之最小生成树最小生成树专题

[kuangbin带你飞]专题六 最小生成树

最小生成树

最小生成树专题

[kuangbin带你飞]专题六 最小生成树 K - The Unique MST (判断最小生成树是否唯一)