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