当前位置:首页 > 洛谷 > 洛谷P1194题:利用Kruskal算法求解商品优惠组合问题

洛谷P1194题:利用Kruskal算法求解商品优惠组合问题

4个月前 (08-04)

洛谷P1194题:利用Kruskal算法求解商品优惠组合问题 洛谷题解 Kruskal算法 最小生成树 并查集 C++ 路径压缩 图论 第1张

一、题目解读

洛谷P1194题要求计算在给定商品单价及优惠组合价格的情况下,购买所有商品的最小总价。题目关键在于如何处理优惠关系,并将其转化为图论中的边权重问题,进而通过算法寻找最优解。

二、解题思路

采用经典的Kruskal算法求解最小生成树。核心思路如下:

1. 虚拟节点构建:引入节点0作为“起点”,与所有商品建立边,权重为商品单价,将问题转化为从0出发覆盖所有节点的最小路径和。

2. 优惠边筛选:仅保留i<j的优惠边(避免重复),降低计算复杂度。

3. Kruskal算法:对边按权重排序,通过并查集逐步合并连通分量,直至生成包含B条边的

三、解题步骤

1. 输入与初始化:读入商品数量B和单价A,初始化边集edges及并查集parent。

2. 构建虚拟边:添加{0,i,A}边至edges,确保每个商品与虚拟节点相连。

3. 读入优惠边:若i<j且存在优惠价格k,添加{i,j,k}至edges。

4. 排序与Kruskal:

    按边权重排序edges。

    遍历边集,若合并u和v节点未形成环,则计入总价并更新并查集。

    当连通分量达到B时终止,总价为最小生成树权重。

四、代码与注释

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

// 边结构(节点u,v,权重w)
struct Edge {
    int u, v, w;
    bool operator<(const Edge& other) const {
        return w < other.w;   // 按权重排序
    }
};

vector<int> parent;   // 并查集父节点数组

// 并查集查找根节点
int find(int x) {
    return parent[x] == x? x : parent[x] = find(parent[x]);  // 路径压缩
}

int main() {
    int A, B;   // A:商品单价,B:商品数量
    cin >> A >> B;
    
    vector<Edge> edges;   // 存储所有边
    
    // 步骤2:添加虚拟节点0到各商品的边
    for (int i = 1; i <= B; ++i) {
        edges.push_back({0, i, A});
    }
    
    // 步骤3:读入优惠价格
    for (int i = 1; i <= B; ++i) {
        for (int j = 1; j <= B; ++j) {
            int k;
            cin >> k;
            if (i < j && k!= 0) {  // 避免重复添加
                edges.push_back({i, j, k});
            }
        }
    }
    
    // Kruskal算法准备
    sort(edges.begin(), edges.end());   // 步骤4:排序
    parent.resize(B + 1);  
    for (int i = 0; i <= B; ++i) parent[i] = i;   // 初始化并查集
    
    int total = 0, count = 0;
    for (auto& e : edges) {
        int rootU = find(e.u);
        int rootV = find(e.v);
        if (rootU!= rootV) {
            parent[rootV] = rootU;   // 合并节点
            total += e.w;
            if (++count == B) break;  // 生成树有B条边
        }
    }
    
    cout << total << endl;
    return 0;
}

五、总结

本解法通过巧妙引入虚拟节点,将商品购买问题转化为最小生成树问题,结合Kruskal算法高效求解。关键在于:

1. 利用并查集优化连通性判断,避免重复计算。

2. 边权重排序与剪枝(仅保留i<j的优惠边)降低时间复杂度。

3. 路径压缩优化并查集查询效率,提升整体性能。


原创内容 转载请注明出处

分享给朋友:

相关文章

力扣1137题:动态规划解泰波那契数 高效求解第N项的秘密

力扣1137题:动态规划解泰波那契数 高效求解第N项的秘密

一:重新解读题目泰波那契数列是一个充满数学趣味的递推序列:从第3项开始,每个数均为前三个数的和(即Tₙ₊₃ = Tₙ + Tₙ₊₁ + Tₙ₊₂)。当给定整数n时,需要高效计算出第n项的值。面对此类递...

牛客DP41精讲:当背包必须装满时,你的状态转移方程该如何调整?

牛客DP41精讲:当背包必须装满时,你的状态转移方程该如何调整?

题目重解我们面对一个经典背包问题的变体:给定n个物品,每个物品有重量w和价值v,背包容量为V。需要回答两个问题:1) 普通情况下能获得的最大价值;2) 必须恰好装满背包时的最大价值(若无法装满则输出0...

IOI 1994 洛谷1216:如何用动态规划高效解决数字三角形问题?附完整代码解析

IOI 1994 洛谷1216:如何用动态规划高效解决数字三角形问题?附完整代码解析

题目重解给定一个由数字组成的三角形结构,从顶部出发,每次可以移动到下方相邻的数字,最终到达底部。我们的目标是找到一条路径,使得路径上经过的数字总和最大。这个问题在实际中有许多应用场景,如最优路径规划、...

【动态规划入门】力扣509题:斐波那契数列的经典解法与优化思路

【动态规划入门】力扣509题:斐波那契数列的经典解法与优化思路

题目解读‌斐波那契数列是一个经典的数学问题,在计算机科学中常被用作算法教学的入门案例。这个神奇的数列从0和1开始,后续每个数字都是前两个数字之和。题目要求我们计算第n个斐波那契数,看似简单的问题背后却...

牛客14496题解:括号最大深度问题(栈思想与代码优化)

牛客14496题解:括号最大深度问题(栈思想与代码优化)

一、题目解读牛客14496题要求计算给定括号字符串中的最大深度。例如,对于字符串 "(()())",最大深度为2。题目考察对括号嵌套结构的理解,以及如何通过编程找到最深嵌套层次。二...

力扣3112题解法:带时间限制的最短路径问题解析(C++代码)

力扣3112题解法:带时间限制的最短路径问题解析(C++代码)

一、题目解读力扣3112题要求解决带时间限制的最短路径问题:给定一个有向图,节点具有消失时间,需计算从起点到各节点的最短路径,且路径总时间不能超过节点的消失时间。题目难点在于需在传统最短路径算法(如D...

发表评论

访客

看不清,换一张

◎欢迎参与讨论,请在这里发表您的看法和观点。