最小生成树、拓扑排序
最小生成树
最小生成树,是用来从一个连通图中计算一个最小使所有点连通所需的权值.
因为要保证权值尽可能小,因此一定不会多连任何一条边. 所以最终选择出来的边连接起来一定是一棵树.
Prim
Prim算法采用与 Dijkstra、Bellman-Ford 算法一样的“蓝白点”思想:白点代表已经进入最小生成树的点,蓝点代表未进入最小生成树的点.
算法描述:(时间复杂度n2(邻接矩阵),邻接表 O(E log(n)) 其中 E 为边数)
以1为起点生成最小生成树,min[v]表示蓝点v与白点相连的最小边权.
MST表示最小生成树的权值之和.
a)初始化:
min[v]=∞(v≠1);min[1]=0;MST=0;
b)
for(i=1;i<=n;i++)
- 寻找min[u]最小的蓝点u;
- 将u标记为白点;
MST+=min[u]
;for 与白点u相连的所有蓝点v
if (w[u][v]<min[v])
min[v]=w[u][v];
c)算法结束: MST即为最小生成树的权值之和
算法分析&思想讲解:
Prim算法每次循环都将一个蓝点u变为白点,并且此蓝点u与白点相连的最小边权min[u]还是当前所有蓝点中最小的. 这样相当于向生成树中添加了n-1次最小的边,最后得到的一定是最小生成树.
实现:
inline void prim(rll x)
{
ans=0;//记录造价
for(rll i=1;i<=n;i++) dis[i]=mp[x][i];//把x放入已选集合,更新其他点到x的距离
dis[x]=0;//x到自己的距离为0
for(rll i=2;i<=n;i++)//只需要找到n-1条边就可以形成一棵最小生成树
{
rll mn=INT_MAX>>1,k;//min找最短的符合要求的边,k记录边的另一节点
for(rll j=1;j<=n;j++)//枚举每一个点,找离已选点最近的边
if(dis[j]<mn&&dis[j])//dis[j]=0表示j点已选
mn=dis[j],k=j;
ans+=dis[k]; dis[k]=0;//dis[k]设为0,表示k点一进入已选点
for(rll j=1;j<=n;j++)//更新其他点到k点的距离
if(dis[j]>mp[k][j]) dis[j]=mp[k][j];
}
}
Kruskal
Kruskal 算法每一次会从剩余的边中选择一条花费最小且不会产生赘余的边,将其变为已选边.
它的主要步骤:先把边按照权值排序;然后加入边时判断加入后是否还是树;如果加入边的两个端点属于两棵不同的树时,将它们合并.
实现:
struct node
{
ll x,y,v,id;
inline friend bool operator<(rg node a,rg node b) { return a.v<b.v; }
}val[maxn];
vector<node> g[maxn];
inline void kruskal()
{
n=read();m=read(); for(rll i=1;i<=n;i++) fa[i]=i;
for(rll i=1,u,v,w;i<=m;i++) u=read(),v=read(),w=read(),g[u].push_back((node) { NULL,v,w,i }),g[v].push_back((node) { u,w,i }),val[i]=(node){u,v,w,i};
sort(val+1,val+m+1);
for(rll i=1,fx,fy;i<=m;i++)
{
fx=find(val[i].x),fy=find(val[i].y);
if(fx^fy) fa[fx]=fy,tot++,sel[val[i].id]=1;
if(tot==n-1) break;
}
}
拓扑排序
拓扑排序是将某些有先后顺序完成的点们按照这种顺序输出.
比如某个点需要完成前面的哪些才可以去完成.
例题:家谱树
有个人的家族很大,辈分关系很混乱,请你帮整理一下这种关系.
给出每个人的孩子的信息.
输出一个序列,使得每个人的后辈都比那个人后列出.
首先把图读进来,然后每一次选择一个没有直接前驱的点输出,并将其从图中删除. 重复这个操作直至图中无点,这时拓扑序就形成了.
#include<bits/stdc++.h>
#define ll int
#define rg register
#define rll rg ll
#define maxn 5001
#define put_ putchar(' ')
#define putn putchar('\n')
using namespace std;
inline ll read()
{
rll f=0,x=0;rg char ch=getchar();while(ch<'0'||ch>'9') f|=ch=='-',ch=getchar();
while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch^'0'),ch=getchar();return f?-x:x;
}
inline void write(rll x) { if(x<0) putchar('-'),x=-x;if(x>9) write(x/10);putchar(x%10|'0'); }
ll t,n,mx,num;
vector<ll> g[maxn];
ll rudu[maxn];
queue<ll> q;
int main()
{
n=read();
for(rll i=1,a;i<=n;i++) while(a=read()&&a) g[i].push_back(a),rudu[a]++;
for(rll i=1;i<=n;i++) if(!rudu[i]) q.push(i);
while(!q.empty())
{
rll t=q.front();q.pop();
for(rll i=0;i<g[t].size();i++)
{
rudu[g[t][i]]--;
if(!rudu[g[t][i]]) q.push(g[t][i]);
}
write(t),put_;
}
return 0;
}
--END--
我的博客: 𝟷𝙻𝚒𝚞
本文链接: https://www.cnblogs.com/1Liu/articles/16755750.html
版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!