【树】最小生成树
最小生成树(MST)
最小生成树:以最小代价连接所有点
Prim 算法
伪代码#
dis[x];//x到最小生成树的距离
任选起点;dis[x]=∞;dis[起点]=0;
for(i=1->n)
{
- 在未标记的点中找到dis[]最小的点u;
- 把u加入最小生成树;(标记u)
- 枚举u的邻居v:
if(v不在最小生成树中)
dis[v]=min(dis[v], u到v边长);
}
写法#
memset(dis,999999,sizeof(dis));
dis[1]=0;
for(int i = 1;i <= n;i++)
{
int u = 0;
for(int j = 1;j <= n;j++)
{
if(!vis[j])
{
if(dis[j] < dis[u]) u=j;
}
}
vis[u]=1;
if(dis[u]>1e9)
{
puts("orz");
return 0;
}
for(int j = 0;j < g[u].size();j++)
{
int v = g[u][j];
if(!vis[v])
{
dis[v] = min(dis[v], w[u][j]);
}
}
}
堆优化#
memset(dis,999999,sizeof(dis));
dis[1]=0;
priority_queue<NODE> q;
q.push(NODE{1,0});
for(int i = 1;i <= n;i++)
{
while(!q.empty() && vis[q.top().id]) q.pop();
if(q.empty())
{
puts("orz");
return 0;
}
int u = q.top().id; q.pop();
vis[u] = 1;
for(int j = 0;j < g[u].size();j++)
{
int v = g[u][j];
if(!vis[v] && dis[v] > w[u][j])
{
dis[v] = w[u][j];
q.push(NODE{v,dis[v]});
}
}
}
Kruskal 算法
从短到长依次取边,如果加入这条边会形成环,那么跳过。
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
struct edge
{
int u,v,w;
}e[100010];
bool cmp(edge a, edge b)
{
return a.w<b.w;
}
int f[10010];
int find(int k)
{
if(f[k] == k) return k;
return f[k] = find(f[k]);
}
void merge(int x, int y)
{
x=find(x),y=find(y);
if(x==y) return;
f[y]=x;
}
int main()
{
int n,m;
cin >> n >> m;
int ans = 0;
for(int i = 1;i <= m;i++)
{
scanf("%d%d%d", &e[i].u, &e[i].v, &e[i].w);
ans += e[i].w;
}
for(int i = 1;i <= n;i++) f[i] = i;
sort(e+1,e+m+1,cmp);
int sum = 0;
for(int i = 1;i <= m;i++)
{
if(find(e[i].u) != find(e[i].v))
{
merge(e[i].u, e[i].v);
sum += e[i].w;
}
}
cout << ans - sum;
return 0;
}
次小生成树
分类#
严格次小生成树:边权和严格小于最小生成树。
非严格次小生成树:非最小生成树剩下的最小生成树。
非严格次小生成树#
枚举最小生成树的边,删掉求最小。
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
int n,m;
struct edge
{
int u,v,w;
}e[100010];
bool vis[100010];
bool cmp(edge a, edge b)
{
return a.w<b.w;
}
int f[10010];
int find(int k)
{
if(f[k] == k) return k;
return f[k] = find(f[k]);
}
void merge(int x, int y)
{
x=find(x),y=find(y);
if(x==y) return;
f[y]=x;
}
long long kruskal(int id)
{
long long sum = 0;
for(int i = 1;i <= n;i++) f[i] = i;
for(int i = 1;i <= m;i++)
{
if(i == id) continue;
if(find(e[i].u) != find(e[i].v))
{
merge(e[i].u, e[i].v);
sum += e[i].w;
}
}
return sum;
}
int main()
{
cin >> n >> m;
for(int i = 1;i <= m;i++)
{
scanf("%d%d%d", &e[i].u, &e[i].v, &e[i].w);
}
long long bef = 0;
sort(e+1,e+m+1,cmp);
for(int i = 1;i <= n;i++) f[i] = i;
for(int i = 1;i <= m;i++)
{
if(find(e[i].u) != find(e[i].v))
{
merge(e[i].u, e[i].v);
vis[i] = 1;
bef+=e[i].w;
}
}
long long ans = 1e18;
for(int i = 1;i <= m;i++)
{
if(vis[i])
{
long long now = kruskal(i);
if(now <= bef) continue;
ans = min(ans, now);
}
}
cout << ans;
return 0;
}
严格次小生成树#
结论:严格次小生成树和最小生成树只有一条边的差距。
int Kruskal(int id) // 返回 跳过第id条边后的最小生成树权值
{
}
对边排序;
做一次Kruskal;
{
标记选中的边;
}
LL ans = 1e18;
for(int i = 1;i <= m;i++)
{
if(i被标记了) continue;
if(e[i].w > maxDis[])
}
作者:蒟蒻Ivan
出处:https://www.cnblogs.com/ghivan911/p/17476046.html
版权:本作品采用「转载请注明出处-非商业性使用」许可协议进行许可。
本博文版权归本博主所有,未经授权不得转载
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!