当前位置: 首页 > article >正文

洛谷题目 P5994 [PA 2014] Kuglarz 题解 (本题较难)

题目传送门:

P5994 [PA 2014] Kuglarz - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

前言:

        本题涉及到最小生成树中的 kruskal  算法和并查集算法,图论基础概念两大知识点,瞎按对莱索没有学过图论的或最小生成树的可能会对这道题无从下手,学过最小生成树和图论的初学者对这道题可以说是非常好的历练。难度可以给到中等偏上(很简单的呀)。

#题目核心目标:

        这道题的很新目标是确定最少花费,从而保证能猜出哪些被子底下藏着球,而解题的关键在于将问题转化成最小生成树问题。本题将详细境界。

##问题分析转化:

        1、信息关联与节点表示:

                把每个被子看做图中的一个节点。对于一个被子序列,我们要确定每个被子是否藏球,而通过魔术师提供的关于区间 [i,j] 内藏球总数奇偶性的信息,就可以逐步推断出每个被子的情况。

                例如,知道区间 [l,r] 的询问都对应途中的一条边,变得两个端点分别是i-1j ,变得权值就是这次询问的花费 c_{i_{j}} 。因为我们可以利用这个区间的奇偶性信息来连接这两个端点所代表的节点状态。

3、问题等价性:

                我们的目标使用最少的花费来获取足够的信息来确定所有杯子里是否藏球,这就相当于在图中找到一个变得集合,使得这些边能够连接所有节点,并且这些边的权值总和最小,恰好就是我们经典的最小生成树问题。

###最小生成树选择-Kruskal 算法:

        1、具体步骤:

                1.1、边的排序:将所有表示询问的边按照花费从小到大进行排序。这里做的目的是优先选择花费晓得询问,以满足最小花费的要求。

                1.2、并查集的使用:

  • 并查集是一种用于处理不相交集合合并与查询问题的数据结构。在本题中,我们使用并查集来判断加入一条边后是否会形成环。
  • 初始时,每个节点的父节点就是它自身,表示每个节点都属于一个独立的集合。
  • 对于每条边,我们查找其两个端点所在集合的根节点。如果两个端点的根节点不同,说明这两个端点属于不同的集合,加入这条边不会形成环,我们就将这条边加入到最小生成树中,并合并这两个集合(即将一个集合的根节点指向另一个集合的根节点)。
  • 如果两个端点的根节点相同,说明这两个端点已经在同一个集合中,加入这条边会形成环,我们就跳过这条边。

####代码:

#include <bits/stdc++.h>
using namespace std;
const int M = 2005;
struct E {
    int u, v, w;
    E(int u, int v, int w) : u(u), v(v), w(w) {}
    bool operator<(const E& t) const {
        return w < t.w;
    }
};
int p[M];
int find(int x) {
    if (p[x] != x) {
        p[x] = find(p[x]);
    }
    return p[x];
}
void un(int x, int y) {
    int rx = find(x);
    int ry = find(y);
    if (rx != ry) {
        p[rx] = ry;
    }
}

int main() {
    int n;
    cin >> n;
    vector<E> e;
    for (int i = 1; i <= n; ++i) {
        for (int j = i; j <= n; ++j) {
            int o;
            cin >> o;
            e.emplace_back(i - 1, j, o);
        }
    }
    for (int i = 0; i <= n; ++i) {
        p[i] = i;
    }
    sort(e.begin(), e.end());

    long long C = 0;
    for (const auto& g : e) {
        int u = g.u;
        int v = g.v;
        int w = g.w;
        int ru = find(u); 
        int ry = find(v);
        if (ru != ry) {
            un(u, v);
            C += w;
        }
    }

    cout << C << endl;

    return 0;
}


http://www.kler.cn/a/522727.html

相关文章:

  • Greenplum临时表未清除导致库龄过高处理
  • 2218. 从栈中取出 K 个硬币的最大面值和
  • 并发编程之美_基础概念与设计哲学
  • Linux学习笔记——磁盘管理命令
  • 利用JSON数据类型优化关系型数据库设计
  • Linux初识——基本指令(2)
  • 深入浅出 Rust 的强大 match 表达式
  • 怎么样把pdf转成图片模式(不能复制文字)
  • PyCharm介绍
  • 宝塔面板SSL加密访问设置教程
  • 自助设备系统设置——对接POS支付
  • 《程序人生》工作2年感悟
  • 蓝桥杯python语言基础(1)——编程基础
  • (2025 年最新)MacOS Redis Desktop Manager中文版下载,附详细图文
  • 【BQ3568HM开发板】如何在OpenHarmony上通过校园网的上网认证
  • USB鼠标的数据格式
  • React 封装高阶组件 做路由权限控制
  • 梯度下降优化算法-Adam
  • 【无标题】规范学生的课堂行为。
  • 指针的介绍2后
  • 【Rust自学】15.7. 循环引用导致内存泄漏
  • Spring AOP原理
  • 智能门锁开发系列:从设计到实现的全面解析
  • Mybaties缓存机制
  • 装饰SpringMVC的适配器实现响应自动包装
  • 每日一题 429. N 叉树的层序遍历