最小权顶点覆盖问题-优先队列分支限界法-C++

问题描述:

给定一个赋权无向图 G=(V,E),每个顶点 v∈V 都有一个权值 w(v)。如果 U⊆V,U⊆V,且对任意(u,v)∈E 有 u∈U 或 v∈U,就称 U 为图 G 的一个顶点覆盖。G 的最小权顶点覆盖是指 G 中所含顶点权之和最小的顶点覆盖。对于给定的无向图 G,设计一个优先队列式分支限界法,计算 G 的最小权顶点覆盖。

算法设计:

为了找到最小权顶点覆盖,这里我们采取优先队列分支限界法来搜索该问题的解空间树。该问题的解空间是一颗子集树,因为对于图中的每一个点,都只有两种选择,加入U集合和不加入U集合,如果扩展开来就会成为一颗二叉树。

要采用优先队列来求解该问题,对于堆中的每一个节点,都有一个目前所选的点的集合,我们需要维护那些已经被选入U集合的点,同时维护当前的点权和,这样每次我们都从堆中选出当前扩展出的节点中点权和最小的一个来扩展,特别的,当点权相同时,我们通过判断当前覆盖集的大小来选择覆盖集大的来扩展。

因为我们采用的是优先队列来查找,我们的目标只是求出一个解,每次从堆中选出的节点都是当前的所有扩展出节点中点权和最小的一个,如果当前节点的状态已经实现了覆盖,那么说明当前已经是最优解了,我们可以直接返回结果。

对于该问题,我们发现无法对每个节点的右儿子进行限界:
因为当右儿子加入U集和时,点权和是不会发生改变的,虽然不加入会让点权和更小,但是不要忽略我们的目标是实现顶点覆盖,我们不扩展右儿子节点就无法保证实现覆盖,所以对右儿子的扩展是必须的。

特别的,在对于当前节点是否覆盖的判断实现中,在这里我们用一个set集合来存储当前U集合顶点可以扩展出的所有节点,这样我们每次查询当前是否覆盖只需要判断set中的元素数目是否等于所有点的数目,这样就可以做到O(1)时间的查询。

对于该问题我们的具体算法流程:
1.读入图的信息,同时初始化优先队列,加入初始的节点。
2.每次从队列中取出当前权值和最小的节点信息,判断是否实现完全覆盖。如果已经是一个完全覆盖集,直接退出搜索,返回结果集。否则需要扩展该结点的左右儿子结点。(对应的,左儿子表示将该结点加入U集合,右儿子代表直接跳过该点)。
3.如果发现当前节点的深度已经大于了节点数目,则说明当前已经搜完所有节点到达了叶子结点,若没有实现完全覆盖则直接退出即可。否则继续进行下一步搜索。

流程图:

在这里插入图片描述

代码:

#include <bits/stdc++.h>
using namespace std;

struct Node {
    int dep; // 深度,第几层就是处理第几个点
    int val; // 权值
    vector<int>U; // U集合
    set<int>st; // 覆盖集

    Node(int dep, int val, vector<int>U, set<int>st):dep(dep), val(val), U(U), st(st) {}
    friend bool operator < (const Node &w1, const Node &w2) {
        if(w1.val == w2.val){
            return w1.st.size() < w2.st.size();
        }
        return w1.val > w2.val;
    }

    friend ostream& operator<<(ostream& os, const Node& p){
        cout << "dep:" << p.dep << " val:" << p.val << " U:";
        for(int i:p.U){
            cout << i << " ";
        }
        cout << " st:";
        for(int i:p.st){
            cout << i << " ";
        }
        return os;
    }
};

struct Whopxx{
    int n;
    vector<int>W; // 点权
    vector<vector<int>>G; // 图
    
    vector<int>bst;
    int bestVal;

    Whopxx(int n,vector<int> w, vector<pair<int,int>> vt):n(n) {
        W = w;
        bst.resize(n + 1);
        G.resize(n + 1);
        for(auto [u, v]:vt){
            G[u].push_back(v);
            G[v].push_back(u);
        }
    }

    void work(){
        priority_queue<Node>q;
        q.push(Node(1, 0, {}, {}));
        while(q.size()){
            Node node = q.top(); q.pop();
            cout << node << endl;
            if(is_cover(node)){ // 当前节点实现全覆盖
                for(int i: node.U){
                    bst[i] = 1;
                }
                bestVal = node.val;
                break;
            }
            if(node.dep > n){ // 搜完叶子结点仍未覆盖
                continue;
            }
            else{
                Node lnode = add(node, node.dep); 
                q.push(lnode); // 左
                
                Node rnode = uadd(node);
                q.push(rnode); // 右
            }
        }
    }

    bool is_cover(Node &node){ // 判断是否为覆盖集
        return node.st.size() == n;
    }
    
    Node add(Node node, int u){ // 加入
        node.U.push_back(u); // 加入U
        node.val += W[u];
        node.dep += 1;
        node.st.insert(u);

        for(auto v: G[u]){
            node.st.insert(v);
        }
        return node;
    }

    Node uadd(Node node){
        node.dep += 1;
        return node;
    }
};

int main(){ 
    freopen("input.txt","r", stdin);
    freopen("output.txt", "w", stdout);

    int n, m;
    cin >> n >> m;
    vector<int>w(n + 1);
    for(int i = 1; i <= n; i++) cin >> w[i];
    vector<pair<int,int>>vt;
    for(int i = 1; i <= m; i++){
        int u, v;cin >> u >> v;
        vt.push_back({u, v});
    }
    Whopxx wx(n, w, vt);
    wx.work();
    cout << wx.bestVal << endl;
    vector<int>ans = wx.bst;
    for(int i = 1;i <= n; i++){
        cout << ans[i] << ' ';
    }

    fclose(stdin);
    fclose(stdout);
    return 0;
}
/*

7 7
1 100 1 1 1 100 10
1 6
2 4
2 5
3 6
4 5
4 6
6 7

5 4
1 100 1 1 1
1 2
3 2
4 2
5 2

4 3
1 100 1 1
1 2
3 2
4 2

4 3
1 3 1 1
1 2
3 2
4 2

4 4
1 2 10 10
1 2
2 3
3 4
4 1

*/

实验测试结果及分析:

测试数据:
input.txt
在这里插入图片描述

根据该数据的建图如下:
在这里插入图片描述

通过运行程序得到:
output.txt
在这里插入图片描述

在该输出结果中,dep代表当前节点所在的深度,val当代表前的点权和,U是所选点的集合,st是当前的覆盖集。通过按优先队列的出点顺序来打印每一个节点的信息,我们可以很清晰的看到整个搜索的过程。

最后两行是问题的最优解,我们选择1,3,4这三个点加入U集合,实现总点权为3的最小顶点覆盖。

复杂度分析:若没有使用优先队列,没有剪枝,直接进行搜索,对于每一个点都有两种情况,也就是最多会扩展2^ n个节点,最坏情况下的时间复杂度为O(2^n),但是由于使用了优先队列来加速查找的过程,由于剪枝策略的存在会使时间复杂度大幅度降低,所以实际的运行时间会远低于该最坏情况下的时间复杂度。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/778841.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

干货分享 | HTTP代理与SOCKS5代理的优缺点

本次我们来聊聊HTTP代理和SOCKS5代理这两种常见的代理协议。了解它们的优缺点和搭建方法&#xff0c;可以帮助你在各种应用场景中选择最合适的代理方式。让我们一起来探索吧&#xff01; HTTP代理的优缺点 优点&#xff1a; 简单易用&#xff1a;HTTP代理主要用于处理HTTP协…

代码随想录算法训练营第23天|LeetCode 39. 组合总和、40.组合总和II、131.分割回文串

1. LeetCode 39. 组合总和 题目链接&#xff1a;https://leetcode.cn/problems/combination-sum/description/ 文章链接&#xff1a;https://programmercarl.com/0039.组合总和.html 视频链接&#xff1a;https://www.bilibili.com/video/BV1KT4y1M7HJ 思路&#xff1a; 本题和…

Java多语言跨境电商外贸商城源码 tiktok商城系统源码 跨境电商源码

Java多语言跨境电商外贸商城源码 tiktok商城系统源码 跨境电商源码 技术栈 PC端使用&#xff1a;vueelementui 用户端使用&#xff1a;uniapp 管理端使用&#xff1a;vueelementui 后台服务使用&#xff1a;springbootmybatisplusmysql 功能描述&#xff1a; 对接PayPal…

统计是一门艺术(非参数假设检验)

1.定义 当总体分布未知&#xff0c;那么就需要一种与分布具体数学形式无关的统计推断方法&#xff0c;称为非参数方法 只能利用样本中的一般信息包括位置和次序关系等 稳健性强 2.符号检验 考虑问题&#xff1a; 小样本情况&#xff1a; 以概率为1/2的二项分布是对称的 两…

idea部署war包成功,但是接口404

场景 项目结构 xxx-xxx-app xxx-xxx-service xxx-xxx-webappapp/webapp依赖service&#xff0c;service中写了各种api&#xff0c;先别管它合不合理&#xff0c;正式环境用webapp发布。 本地配置tomcat启动&#xff0c;但是发现每次部署成功&#xff0c;但是service中的接口…

使用Ubuntu 22.04安装Frappe-Bench【二】

系列文章目录 第一章 使用VMware创建Ubuntu 22.04【一】 文章目录 系列文章目录前言什么是Frappe-Bench&#xff1f;使用安装ERPNext能实现什么效果&#xff1f; 官网给了一个说明 一、使用Ubuntu 22.04安装Frappe-Bench一、安装要求二、安装命令三、 可能出现问题 总结 前言 …

hnust 1816: 算法10-9:简单选择排序

hnust 1816: 算法10-9&#xff1a;简单选择排序 题目描述 选择排序的基本思想是&#xff1a;每一趟比较过程中&#xff0c;在n-i1(i1,2,…,n-1)个记录中选取关键字最小的记录作为有序序列中的第i个记录。 在多种选择排序中&#xff0c;最常用且形式最为简单的是简单选择排序。…

JavaScript中的立即执行函数表达式(Immediately Invoked Function Expression, IIFE)

聚沙成塔每天进步一点点 本文回顾 ⭐ 专栏简介JavaScript中的立即执行函数表达式&#xff08;Immediately Invoked Function Expression, IIFE&#xff09;1. 引言2. IIFE的概念2.1 概述2.2 语法2.3 历史背景 3. IIFE的作用3.1 创建独立作用域3.2 模块化代码3.3 防止变量提升3.…

动态路由--RIP配置(思科cisco)

一、简介 RIP协议&#xff08;Routing Information Protocol&#xff0c;路由信息协议&#xff09;是一种基于距离矢量的动态路由选择协议。 在RIP协议中&#xff0c;如果路由器A和网络B直接相连&#xff0c;那么路由器A到网络B的距离被定义为1跳。若从路由器A出发到达网络B需要…

Apache Seata分布式事务启用Nacos做配置中心

本文来自 Apache Seata官方文档&#xff0c;欢迎访问官网&#xff0c;查看更多深度文章。 本文来自 Apache Seata官方文档&#xff0c;欢迎访问官网&#xff0c;查看更多深度文章。 Seata分布式事务启用Nacos做配置中心 Seata分布式事务启用Nacos做配置中心 项目地址 本文作…

FreeU: Free Lunch in Diffusion U-Net——【代码复现】

这篇文章发表于CVPR 2024&#xff0c;官网地址&#xff1a;ChenyangSi/FreeU: FreeU: Free Lunch in Diffusion U-Net (CVPR2024 Oral) (github.com) 一、环境准备 提前准备好python、pytorch环境 二、下载项目依赖 demo下有一个requirements.txt文件&#xff0c; pip inst…

Fill - UVA 10603

网址如下&#xff1a; Fill - UVA 10603 - Virtual Judge (vjudge.net) 感觉有点浮躁&#xff0c;没法完全将思绪投入题的思考中 脑袋糊糊的 一道bfs题 代码如下&#xff1a; #include<queue> #include<cstdio> #include<cstring> #include<vector&g…

开放式耳机哪个牌子好?悠律、漫步者、韶音全面对比与推荐

对于现在的无线耳机市场而言&#xff0c;开放式耳机迎来的真正的大爆发&#xff0c;关键的是它采用了定向传声方式&#xff0c;我们在运动时除了可以感受到音乐带来的快乐外&#xff0c;还能时刻保持对外界环境音的警觉。 今天&#xff0c;我们将为大家详细对比推荐三款备受瞩…

Redis中list类型操作命令(操作演示、命令语法、返回值、时间复杂度、注意事项等)

文章目录 lpush 命令lrange 命令lpushx 命令rpush 命令rpushx 命令lpop 命令rpop 命令lindex 命令linsert 命令llen 命令lrem 命令ltrim 命令lset 命令blpop 和 brpop lpush 命令 从左侧向列表中插入指定的元素 语法&#xff1a;lpush key value [value……] 时间复杂度&#…

大厂面试官赞不绝口的后端技术亮点【后端项目亮点合集(2)】

本文将持续更新~~ hello hello~ &#xff0c;这里是绝命Coding——老白~&#x1f496;&#x1f496; &#xff0c;欢迎大家点赞&#x1f973;&#x1f973;关注&#x1f4a5;&#x1f4a5;收藏&#x1f339;&#x1f339;&#x1f339; &#x1f4a5;个人主页&#xff1a;绝命C…

第三方商城对接重构(HF202407)

文章目录 项目背景一、模块范围二、问题方案1. 商品模块整体来说这块对接的不是太顺利,梳理了几条大概的思路:2. 订单模块3. 售后4. 发票5. 结算单经验总结项目背景 作为供应商入围第三方商城成功,然后运营了一段时间,第三方通知要重构, 需要重新对接打通接口完成系统对接…

【网络管理工具】NETworkManager工具的基本使用教程

【网络管理工具】NETworkManager工具的基本使用教程 一、NETworkManager工具介绍1.1 NETworkManager简介1.2 NETworkManager特点1.3 NETworkManager使用场景 二、下载NETworkManager软件包2.1 下载地址2.2 下载软件 三、运行NETworkManager工具3.1 解压NETworkManager3.2 运行N…

WPF中Background=“{x:Null}“ 和 Transparent

WPF中关于背景透明和背景无 此时&#xff0c;我代码中是写的有有个控件&#xff0c;一个Border &#xff0c;一个TextBox &#xff0c;范围都是全屏这么大&#xff0c;可以输入TextBox 因为&#xff0c;当border没有设置背景的时候&#xff0c;实际上是&#xff1a; <Borde…

实现原理:远程过程调用(RPC)

Hi~&#xff01;这里是奋斗的小羊&#xff0c;很荣幸您能阅读我的文章&#xff0c;诚请评论指点&#xff0c;欢迎欢迎 ~~ &#x1f4a5;&#x1f4a5;个人主页&#xff1a;奋斗的小羊 &#x1f4a5;&#x1f4a5;所属专栏&#xff1a;C语言 &#x1f680;本系列文章为个人学习…

Linux多进程和多线程(七)进程间通信-信号量

进程间通信之信号量 资源竞争 多个进程竞争同一资源时&#xff0c;会发生资源竞争。 资源竞争会导致进程的执行出现不可预测的结果。 临界资源 不允许同时有多个进程访问的资源, 包括硬件资源 (CPU、内存、存储器以及其他外 围设备) 与软件资源(共享代码段、共享数据结构) …