最小生成树和最小树形图
最小生成树 是在无向图中 是把所有点连接的最小边值;
pri 算法:
贪心的思想,每次选择那个入边最短的边。去更新
利用并查集判断2个点是不是已经间接相连了
理解: 相当于 所有人要进入一个场地,如何让所有的人的费用最小。 (人一个一个进去)
s算法
#include <bits/stdc++.h> using namespace std; #define ri register int #define M 200005 #define N 5005 int fa[N]; struct edge{ int a,b; int val; bool operator <(const edge &t)const { return val<t.val; } }p[M]; int findd(int a) { if(fa[a]==a) return a; fa[a]=findd(fa[a]); //检查的时候每一步都要好好看,看函数进去的值是什么 是上层的父亲 return fa[a]; } int n,m; long long ans; int main(){ scanf("%d%d",&n,&m); for(ri i=1;i<=m;i++) { int a,b,c; scanf("%d%d%d",&a,&b,&c); p[i].val=c; p[i].a=a,p[i].b=b; } sort(p+1,p+1+m); for(ri i=1;i<=n;i++) fa[i]=i; int trmp=0; for(ri i=1;i<=m;i++) { int l=findd(p[i].a); int r=findd(p[i].b); if(l==r) continue ; if(l!=r) { fa[l]=r; ans+=p[i].val; trmp++; } } if(trmp==n-1) printf("%lld",ans); else printf("orz"); return 0; }
不能用prm 算法解决 最小树形图
最小树形图 是有向图的最小生成树
算法 zhuliu
思想: 从入度入手+缩点的+最小边的思想(每一个点弄一个dis【最小边的值】,保存他的前一个);
void zl() { while(1){ for(ri i=1;i<=n;i++) dis[i]=inf; // 利用了尽量找边最小的思想 for(ri i=1;i<=m;i++) { int u,v; u=p[i].u,v=p[i].v; if(v!=u&&dis[v]>p[i].val){ pre[v]=u; dis[v]=p[i].val; } } for(ri i=1;i<=n;i++) { if(dis[i]==inf&&i!=root) // 不存在的情况 { printf("-1"); exit(0); } } int cnt=0; for(ri i=1;i<=n;i++) vis[i]=0,id[i]=0; for(ri i=1;i<=n;i++) { if(i==root) continue; ans+=dis[i]; int v=i; while(vis[v]!=i&&!id[v]&&v!=root) /// 找环 { vis[v]=i; v=pre[v]; } if(!id[v]&&v!=root) // 只要不是那2个特殊的情况,代表找到了。 { id[v]=++cnt; for(int u=pre[v];u!=v;u=pre[u]) { id[u]=cnt; } } } if(!cnt) { printf("%d",ans); exit(0); } for(ri i=1;i<=n;i++) { if(!id[i]) id[i]=++cnt; } for(ri i=1;i<=m;i++) { int v=p[i].v, u=p[i].u; //////// 新编号 p[i].v=id[v]; p[i].u=id[u]; if(id[u]!=id[v]) { p[i].val-=dis[v]; } } n=cnt; root = id[root]; } }