2.15总结

本文介绍了最小生成树的Prim算法和Kruskal算法,并通过实例展示了如何运用这两种算法解决洛谷平台上的题目。在上午的学习中,作者深入理解了Kruskal算法,通过模板完成了P3366题目的解答。下午,作者又分别应用模板解决了P2121和P1195题目,进一步巩固了最小生成树的概念。晚上,虽然在P1991题目上遇到困难,但明确了思路,即寻找最大距离以确定无线通讯网的覆盖范围。
摘要由CSDN通过智能技术生成

1.上午三个半小时

学习了最小生成树的prim算法和kruskal算法的基本知识,但因为之前学过并查集,所以对kruskal算法比较熟悉,今天的题目都是用的kruskal算法,后面会尝试用prim算法。

完成了一个题目。

P3366 【模板】最小生成树

P3366 【模板】最小生成树 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

思路

首先把每个点的父母结点初始化为结点本身,然后每次加入长度最小的边,判断该边的两个顶点是否在一个集合内,在的话就不要改变什么,否则就把两个点所在的集合并拢,把边的总数、边的长度的总和更新,最后看单独的点,也就是父母节点没有更新的点的数量是否大于一,因为只有根结点的父母结点不变。

代码实现

#include<bits/stdc++.h>
using namespace std;
struct node
{
    int x,y,z;
} edge[200001];
bool cmp(node a,node b)
{
    return a.z < b.z;
}
int fa[200001];
int n,m;
int u,v,w;
int sum;
int get(int x)
{
    return x == fa[x] ? x : fa[x] = get(fa[x]);
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i = 1; i <= m; i ++)
    {
        scanf("%d%d%d",&edge[i].x,&edge[i].y,&edge[i].z);
    }
    for(int i = 0; i <= n; i ++)
    {
        fa[i] = i;
    }
    sort(edge + 1,edge + 1 + m,cmp);
    // 每次加入一条最短的边
    for(int i = 1; i <= m; i ++)
    {
        int x = get(edge[i].x);
        int y = get(edge[i].y);
        if(x == y) continue;
        fa[y] = x;
        sum += edge[i].z;
    }
    int ans = 0;
    for(int i = 1; i <= n; i ++)
    {
        if(i == fa[i]) ans ++;
    }
    if(ans > 1) puts("orz");
    else printf("%d",sum);
    return 0;
}

2.下午四个小时

完成了两个题目。

P2121 拆地毯

P2121 拆地毯 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

思路

思路和模板相似,套用模板,这题比模板多了地毯条数这个要求。

代码实现

#include<bits/stdc++.h>
using namespace std;
int n,m,k,sum,ans;
int parent[100001];
struct node
{
    int u;
    int v;
    int w;
} edge[100001];
bool cmp(node x,node y)
{
    return x.w>y.w;
}
int Find(int x)
{
    return x == parent[x] ? x : parent[x] = Find(parent[x]);
}
int main()
{
    scanf("%d %d %d",&n,&m,&k);
    for(int i=1;i<=m;i++)
        scanf("%d %d %d",&edge[i].u,&edge[i].v,&edge[i].w);
    for(int i=1;i<=n;i++)
        parent[i]=i;
    sort(edge+1,edge+m+1,cmp);
    for(int i=1;i<=m;i++)
    {
        int u = Find(edge[i].u);
        int v = Find(edge[i].v);
        if(u == v) continue;
        parent[v] = u;
        ans++;
        if(ans>k)
            break;
        sum += edge[i].w;
    }
    printf("%d",sum);
    return 0;
}

P1195 口袋的天空

P1195 口袋的天空 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

思路

继续套用模板,但这个题是要合成规定数量的棉花糖,也就是生成规定数量的树,所以我们如果想要连出k棵树,就需要连n-k条边,如果最终的边数少于n-k,就不可能合成k朵棉花糖,当边数等于n-k时,最小的代价就产生了。

代码实现

#include<bits/stdc++.h>
using namespace std;
int n,m,k,sum,ans;
int parent[100001];
struct node
{
    int u;
    int v;
    int w;
} edge[100001];
bool cmp(node x,node y)
{
    return x.w<y.w;
}
int Find(int x)
{
    return x == parent[x] ? x : parent[x] = Find(parent[x]);
}
int main()
{
    scanf("%d %d %d",&n,&m,&k);
    for(int i=1;i<=m;i++)
        scanf("%d %d %d",&edge[i].u,&edge[i].v,&edge[i].w);
    for(int i=1;i<=n;i++)
        parent[i]=i;
    sort(edge+1,edge+m+1,cmp);
    for(int i=1;i<=m;i++)
    {
        int u = Find(edge[i].u);
        int v = Find(edge[i].v);
        if(u == v)
            continue;
        parent[v] = u;
        ans++;
        sum += edge[i].w;
        if(ans>=n-k)
        {
            printf("%d",sum);
            break;
        }
    }
    if(ans<n-k)
        printf("No Answer");
    return 0;
}

3.晚上一个小时

一个题目没有完全写出来,还要一些错误。先挖个坑,等会再来填。

P1991 无线通讯网

P1991 无线通讯网 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

思路

因为装了卫星电话的哨所之间无论多远都能连通,所以我们就需要把卫星电话装给距离最远的几个哨所,然后去剩下的哨所之间最大的距离定为无线电收发器的最小距离。先算一下每个点之间的距离,然后将两个点和它们之间的距离用结构体数组存起来,同时算一下边的总数,然后每次选取最短的边加入,更新树的结点,找到结点之间最长的距离,最后输出即可。

错误

距离公式不要写错。

计算点之间的距离的时侯,是用sum,而不是i。

代码实现

#include<bits/stdc++.h>
#include<math.h>
using namespace std;
int s,p,sum;
double d=0;
int parent[501];
struct node
{
    int u;
    int v;
    double w;
} edge[250001];
struct pointer
{
    double x;
    double y;
} point[501];
bool cmp(node a,node b)
{
    return a.w<b.w;
}
int Find(int o)
{
    return o == parent[o] ? o : parent[o] = Find(parent[o]);
}
int main()
{
    scanf("%d %d",&s,&p);
    for(int i=1; i<=p; i++)
        scanf("%lf %lf",&point[i].x,&point[i].y);
    for(int i=1; i<=p; i++)
        for(int j=1; j<i; j++)
        {
            edge[++sum].u=i;
            edge[sum].v=j;
            edge[sum].w=sqrt((point[i].x-point[j].x)*(point[i].x-point[j].x)+(point[i].y-point[j].y)*(point[i].y-point[j].y));
        }
    for(int i=1; i<=p; i++)
        parent[i]=i;
    sort(edge+ 1,edge + 1 + sum,cmp);
    int ss=0;
    for(int i = 1; i <=sum; i ++)
    {
        int u = Find(edge[i].u);
        int v = Find(edge[i].v);
        if(u == v)
            continue;
        parent[v] =u;
        if(d<edge[i].w)
            d=edge[i].w;
        ss++;
        if(ss>=p-s)
            break;
    }
    printf("%.2lf",d);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值