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

news2024/10/5 14:10:40

问题描述:

给定一个赋权无向图 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),但是由于使用了优先队列来加速查找的过程,由于剪枝策略的存在会使时间复杂度大幅度降低,所以实际的运行时间会远低于该最坏情况下的时间复杂度。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

AttackGen:一款基于LLM的网络安全事件响应测试工具

关于AttackGen AttackGen是一款功能强大的网络安全事件响应测试工具&#xff0c;该工具利用了大语言模型和MITRE ATT&CK框架的强大功能&#xff0c;并且能够根据研究人员选择的威胁行为组织以及自己组织的详细信息生成定制化的事件响应场景。 功能介绍 1、根据所选的威胁行…

springboot项目多模块工程==1搭建

1、新建父工程 采用springboot工程作为父工程搭建方便依赖选择&#xff0c;在这个基础上进行maven的pom父子模块结构调整。该工程选择mave进行依赖管理 2、springboot 版本及相关依赖选择 3、删除工程目录src,并修改pom 由于该父工程只作为依赖的统一管理&#xff0c;因此将…

Python实战训练(方程与拟合曲线)

1.方程 求e^x-派&#xff08;3.14&#xff09;的解 用二分法来求解&#xff0c;先简单算出解所在的区间&#xff0c;然后用迭代法求逼近解&#xff0c;一般不能得到精准的解&#xff0c;所以设置一个能满足自己进度的标准来判断解是否满足 这里打印出解x0是因为在递归过程中…

CentOS 7安装Elasticsearch7.7.0和Kibana

一. 准备安装包 elasticsearch和kibana&#xff1a;官网历史版本找到并下载&#xff08;https://www.elastic.co/cn/downloads/past-releases#elasticsearch&#xff09;ik分词器&#xff1a;GitHub下载&#xff08;https://github.com/infinilabs/analysis-ik/releases/tag/v…

3.js - 裁剪平面(clipIntersection:交集、并集)

看图 代码 // ts-nocheck// 引入three.js import * as THREE from three// 导入轨道控制器 import { OrbitControls } from three/examples/jsm/controls/OrbitControls// 导入lil.gui import { GUI } from three/examples/jsm/libs/lil-gui.module.min.js// 导入tween import …

Interpretability 与 Explainability 机器学习

「AI秘籍」系列课程&#xff1a; 人工智能应用数学基础人工智能Python基础人工智能基础核心知识人工智能BI核心知识人工智能CV核心知识 Interpretability 模型和 Explainability 模型之间的区别以及为什么它可能不那么重要 当你第一次深入可解释机器学习领域时&#xff0c;你会…

WEB编程-了解Tomcat服务器

第⼀章⽹络编程 1.1 概述 计算机⽹络&#xff1a;是指将地理位置不同的具有独⽴功能的多台计算机及其外部设备&#xff0c;通过通信线路连接起来&#xff0c;在⽹络 操作系统、⽹络管理软件及⽹络通信协议的管理和协调下&#xff0c;实现资源共享和信息传递的计算机系统。 …

cs224n作业3 代码及运行结果

代码里要求用pytorch1.0.0版本&#xff0c;其实不用也可以的。 【删掉run.py里的assert(torch.version “1.0.0”)即可】 代码里面也有提示让你实现什么&#xff0c;弄懂代码什么意思基本就可以了&#xff0c;看多了感觉大框架都大差不差。多看多练慢慢来&#xff0c;加油&am…

前端位置布局汇总

1、位置&#xff1a;绝对位置和相对位置 绝对位置 style"position: absolute;left: 218px;top: 0%;" style"position: absolute;bottom:5px;right:5px ;" 相对位置 :margin外边距 padding内边距 style"border:1px solid black;width:200px;text-ali…

vue事件处理v-on或@

事件处理v-on或 我们可以使用v-on指令&#xff08;简写&#xff09;来监听DOM事件&#xff0c;并在事件触发时执行对应的Javascript。用法&#xff1a;v-on:click"methodName"或click"hander" 事件处理器的值可以是&#xff1a; 内敛事件处理器&#xff1…

Yolo v7网络实现细节(一)

Yolo v7网络实现细节 YOLO v7网络架构的整体介绍 不同GPU和对应模型&#xff1a; ​​​​​​​边缘GPU&#xff1a;YOLOv7-tiny普通GPU&#xff1a;YOLOv7​​​​​​​云GPU的基本模型&#xff1a; YOLOv7-W6 激活函数&#xff1a; YOLOv7 tiny&#xff1a; leaky ReLU其…

南方健康2024米思会:科普患教赋能医药增长闭环,千亿蓝海市场大爆发!

2024年6月25日-28日&#xff0c;在中国•南太湖举办的2024米思会如约而至&#xff0c;顺利落下帷幕&#xff0c;本次大会以“韧进启新局”为主题&#xff0c;以不懈进取的“韧劲”&#xff0c;立身破局&#xff0c;迎变启新。通过4天3夜的思想碰撞和互动交流&#xff0c;引领行…

使用shell脚本实现DM8开机自动启动

编写shell脚本 #!/bin/bashsu -dmdba >>EOF cd /home/dmdba/dmdbms/bin ./DmServiceDMTEST start echo "dm start ... " EOF注意&#xff1a;DmServiceDMTEST每个服务器设置的不一样&#xff0c;根据实际进行更换 授权脚本可执行权限 chmod -x /dmdata/dmse…

策略为王股票软件源代码-----如何修改为自己软件61----资讯菜单修改-----举例---------调用同花顺网页------

http://stock.sina.com.cn 将原来的新浪行情,修改为同花顺, 搜索 stock.sina.com.cn... StkUI\View\InfoView.cpp(58):char

【C++:默认成员函数初始化列表】

构造函数 特点 没有返回值支持函数重载对象实例化时&#xff0c;编译器自动调用作用不是构造&#xff0c;而是初始化函数名与类名相同无参函数和全缺省的函数&#xff0c;不用传参就能调用的函数叫做默认构造函数 构造函数是一个特殊的成员函数 注&#xff1a;无参构造函数在实…

Lock4j简单的支持不同方案的高性能分布式锁实现及源码解析

文章目录 1.Lock4j是什么?1.1简介1.2项目地址1.3 我之前手写的分布式锁和限流的实现 2.特性3.如何使用3.1引入相关依赖3.2 配置redis或zookeeper3.3 使用方式3.3.1 注解式自动式3.3.2 手动式 4.源码解析4.1项目目录4.2实现思路 5.总结 1.Lock4j是什么? 1.1简介 lock4j是苞米…

平均102天 Accept的国产医学顶刊,影响因子4连涨,还免版面费!

《Asian Journal of Pharmaceutical Sciences》 (亚洲药物制剂科学) 是由沈阳药科大学主办、Elsevier合作出版的全英文药剂学学术期刊&#xff0c;是“中国科技期刊卓越行动计划”资助期刊&#xff0c;现已被SCIE、PubMed Central、Scopus和DOAJ等国际著名检索系统收录&#xf…

【已解决】“import ... =“ 只能在 TypeScript 文件中使用

现象 在使用 import 语法的时候&#xff0c;代码报红&#xff0c;提示&#xff1a;“import ... “ 只能在 TypeScript 文件中使用 原因 代码被 VSCode 解析成 TypeScript 语法 解决方案&#xff1a; 关闭 JavaScript 的验证启用即可。 mac 快捷方式&#xff1a;comman s…

25.【C语言】循环结构之for 上

1.基本使用 类比while 在while循环中&#xff0c;有三个不可或缺的部分&#xff1a;初始化&#xff0c;判断部分&#xff0c;调整部分 int i 0;//初始化 while (i < 10)//判断部分 {……i;//调整部分 }三个部分太分散&#xff0c;用for循环可集为一体&#xff0c;简洁 …

【海贼王的数据航海】ST表——RMQ问题

目录 1 -> RMQ问题 1.1 -> 定义 1.2 -> 解决策略 2 -> ST表 2.1 -> 定义 2.2 什么是可重复贡献问题 2.3 -> 预处理ST表 2.4 -> 处理查询 2.5 -> 实际问题 1 -> RMQ问题 1.1 -> 定义 RMQ (Range Minimum/Maximum Query)即区间最值查询…