最小生成树—>无向图
常见的用法
1)稠密图 —> Prim算法朴素版
2)稀疏图 —> Kruskal算法
二分图:
1)染色法 —>判断是否是二分图 O(n+m)
2)匈牙利算法 —>求最大匹配 O(mn) 实际运用效果非常好
3)最大流问题
大纲:
朴素版Prim算法 (核心:算法流程)
1)初始化距离 dist[i]<–0x3f
算法流程:
最小生成树解决的问题:
1)最小连通距离
2)相当于去除垄余的边,每个点保留一条最短边
最小生成树不会有环:边权正负均可以
注意:先累加,再更新 (如果有自环,更新之后,自己会变小)
int prim()
{
memset(dist, 0x3f, sizeof dist);
int res = 0;
for (int i = 0; i < n; i ++ )
{
int t = -1;
//寻找不在队中最小的点
for (int j = 1; j <= n; j ++ )
if (!st[j] && (t == -1 || dist[t] > dist[j]))
t = j;
if (i && dist[t] == INF) return INF;
if (i) res += dist[t];
st[t] = true;
//更新其他点
for (int j = 1; j <= n; j ++ ) dist[j] = min(dist[j], g[t][j]);
}
return res;
}
Kruskal算法: 效果非常好,很快
算法描述:
并查集: O(1)
1)在a,b之间加一条边
2)判断是否连通
特点:只需要开个结构体存储边就可以了
struct Edge{
int a,b,w;
bool operator< (const Edge &W)const
{
return w < W.w;
}
}Edges[M];
int find(int x)
{
if(p[x]!=x) p[x]=find(p[x]);
return p[x];
}
int kruskal()
{
sort(Edges,Edges+m);
for(int i=1;i<=n;i++) p[i]=i;
int res=0,cnt=0;
for(int i=0;i<m;i++)
{
int a=Edges[i].a,b=Edges[i].b,w=Edges[i].w;
if(find(a)!=find(b))
{
p[find(a)]=find(b);
res+=w;
cnt++;
}
}
if(cnt<n-1) return INF;
else
return res;
}
res+=w;
cnt++;
}
}
if(cnt<n-1) return INF;
else
return res;
}