最小生成树



首先,生成树是指在一个连通图中的连通子图,hanyou图中全部n个顶点,但只有足以构成一棵树的n-1条边。一颗有n个顶点的生成树有且仅有n-1条边,如果生成树中再添加一条边,则必定成环。

而最小生成树则是指在连通网的所有生成树中,所有的代价和最小的生成树。

Kruskal算法

思路:初始边数为1,每迭代一次就选择最小(或者最大,看题目要求),加入到最小 生成树的边集合中。

实现步骤:

1.把图中所有边按照权值从大到小(或从小到大)排序。

2.把图中的n个顶点看成独立的n棵组成的集合。

3.按照排序的权值排边,所选的边连接的两个顶点应属于两颗不同的数,(如用的并查集即两个顶点的父亲节点不同),则成为最小生成树的一条边,并且将着两棵树合并成一棵树。重复此步骤直到所有顶点都在一颗数内或者有n-1条边为止。

接下来通过题目理解:

并查集实现

题目链接:传送门

下边有模板题的传送门。

题目:

又到了一年一度的明明生日了,明明想要买 BB 样东西,巧的是,这 BB 样东西价格都是 AA 元。

但是,商店老板说最近有促销活动,也就是:

如果你买了第 II 样东西,再买第 JJ 样,那么就可以只花 K_{I,J}KI,J? 元,更巧的是,K_{I,J}KI,J? 竟然等于 K_{J,I}KJ,I?

现在明明想知道,他最少要花多少钱。

输入:

第一行两个整数,A,BA,B

接下来 BB 行,每行 BB 个数,第 II 行第 JJ 个为 K_{I,J}KI,J?

我们保证 K_{I,J}=K_{J,I}KI,J?=KJ,I? 并且 K_{I,I}=0KI,I?=0

特别的,如果 K_{I,J}=0KI,J?=0,那么表示这两样东西之间不会导致优惠。

输出:

一个整数,为最小要花的钱数。

通过题目不难看出,当买了一件商品后另一件产品将可能以低价售出,这样我们就可以把每个礼物看成一个顶点,将一件产品与买过这件产品后会降价的产品连接起来,权值为降价后商品的价格。然后用最小生成树遍历一遍即可。

但仔细想一下,入度为零的顶点产品的价格又要怎么存储呢?这里就要用上一个小技巧:即每一条边从0开始连接,那么与0相连的权值自然就是入度为0的产品的价格了。

上代码:

#include
using namespace std;
const int maxn=300000;
int a,b,k,f[maxn],ans;
struct node{
    int u,v,w;
}t[maxn];//结构体存边与权值。
int find(int x)
{
    if(x==f[x])
        return x;
    return f[x]=find(f[x]);
}
bool cmp(node A,node B)
{
    return A.wb)//如果所需每个顶点都遍历过了直接退出。
            break;
        if(find(t[i].u)!=find(t[i].v)){//步骤三核心思想.
            cnt++;
            ans+=t[i].w;
            to(t[i].u,t[i].v);
        }
    }
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    cin>>a>>b;
    for(int i=1;i<=b;i++){
        for(int j=1;j<=b;j++){
            int op;
            cin>>op;
            if(i

Prim算法

思路:每次迭代选择代价最小的边对应的点,加入到最小生成树中。算法从某一个顶点s开始,逐渐长大覆盖整个连通网的所有顶点。

  1. 图的所有顶点集合为VV;初始令集合u={s},v=V?uu={s},v=V?u;
  2. 在两个集合u,vu,v能够组成的边中,选择一条代价最小的边(u0,v0)(u0,v0),加入到最小生成树中,并把v0v0并入到集合u中。
  3. 重复上述步骤,直到最小生成树有n-1条边或者n个顶点为止。

模板题传送门

模板题就不贴题目了。

#include
using namespace std;
int n,m,ans,cnt,k,dis[5005],check[5005],head[200002];
struct node{
    int to,w,next;
}e[400004];
void add(int u,int v,int w)
{
    e[k].to=v;
    e[k].w=w;
    e[k].next=head[u];
    head[u]=k++;
}
typedef pairP;
priority_queue,greater

>q; void prim() { dis[1]=0; q.push({0,1}); while(!q.empty()&&cnt>n>>m; memset(dis,127,sizeof(dis)); memset(head,-1,sizeof(head)); for(int i=1;i<=m;i++) { int a,b,c; cin>>a>>b>>c; add(a,b,c); add(b,a,c); } prim(); if(cnt==n) cout<

相关