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

LA 2038 Strategic game(最小点覆盖,树形dp,二分匹配)

题意即求一个最小顶点覆盖。

对于没有孤立点的图G=(V,E),最大独立集+最小顶点覆盖= V。(往最大独立集加点)

问题可以变成求树上的最大独立集合。

每个结点的选择和其父节点选不选有关,

dp(u,1)表示父节点选,这时u不可选,

dp(u,0)表示父节点不选,这时u可选可不选。

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

const int maxn = 1501;
int meo[maxn][2];
int vis[maxn][2], clk;
int hd[maxn],nx[maxn<<1],to[maxn<<1],ec;

void add(int u,int v)
{
    to[ec] = v;
    nx[ec] = hd[u];
    hd[u] = ec++;
}

int dp(int u,int a = 0,int f = -1)//a表示父节点选不选
{
    if(vis[u][a] == clk) return meo[u][a];
    vis[u][a] = clk;
    int &re = meo[u][a];
    re = 0;
    int pick = 1;
    for(int i = hd[u]; ~i; i = nx[i]){
        int v = to[i];
        if(v == f) continue;
        if(!a){
            pick += dp(v,1,u);
        }
        re += dp(v,0,u);
    }
    if(!a) re = max(re,pick);
    return re;
}

//#define LOCAL
int main()
{
#ifdef LOCAL
    freopen("in.txt","r",stdin);
#endif
    int n;
    while(~scanf("%d",&n)){
        memset(hd,-1,sizeof(hd)); ec = 0;
        for(int i = 0; i < n; i++){
            int u,sn; scanf("%d:(%d)",&u,&sn);
            while(sn--){
                int v;scanf("%d",&v);
                add(u,v); add(v,u);
            }
        }
        clk++;
        printf("%d\n",n-dp(0));
    }
    return 0;
}

最小点覆盖还可以用二分匹配来做

关键代码,下面可以适合无向图,如果用有向图的算法一个匹配会算两次。

int link[maxn];
int vis[maxn], clk;

bool aug(int u)
{
    if(vis[u] == clk) return false;
    vis[u] = clk;
    for(int i = hd[u]; ~i; i = nx[i]){
        int v = to[i];
        if(!~link[v] || aug(link[v])){
            link[v] = u;
            link[u] = v;
            return true;
        }
    }
    return false;
}

int Hungary(int n)
{
    memset(link,-1,sizeof(link));
    int ans = 0;
    for(int i = 0; i < n; i++){
        if(link[i]<0){
            clk++;
            if(aug(i)) ans++;
        }
    }
    return ans;
}

也可以直接dp求最小点覆盖集合,

f[u][p]表示以u为根的树最小点覆盖,p表示选不选u。

当选u的时候,子结点可选可不选,

当不选u的时候,子结点都选。

(实际上存在在某些结点只选一个子节点的最优解的情况,但是这样做并不会丢解)

int f[maxn][2],vis[maxn],clk;

void dfs(int u = 0,int fa = -1)
{
    vis[u] = clk;
    f[u][0] = 0; f[u][1] = 1;
    for(int i = hd[u]; ~i; i = nx[i]){
        int v = to[i];
        if(v == fa) continue;
        if(vis[v] != clk) dfs(v,u);
        f[u][1] += min(f[v][0],f[v][1]);
        f[u][0] += f[v][1];
    }
}

 

转载于:https://www.cnblogs.com/jerryRey/p/4854823.html

相关文章:

  • VMWare下虚拟机NAT共享方式上网的配置说明
  • hadoop中遇到的问题。
  • Android基础小技术点:Android ListView设置背景图片及分割线、周边距
  • 结构体
  • zabbix vfs.fs.discovery过滤
  • 主键生成
  • RDVTabBarController--可自由定制的iOS底部导航控件
  • 智能园区报修系统可行性分析
  • 堆排序学习笔记及堆排序算法的python实现
  • Golang 并发简介
  • Python_cmd的各种实现方法及优劣(subprocess.Popen, os.system和commands.getstatusoutput)
  • url 中文传参 乱码问题
  • Android签名机制
  • libsuperuser简介
  • Linux缓存释放
  • 【译】JS基础算法脚本:字符串结尾
  • 【译】React性能工程(下) -- 深入研究React性能调试
  • canvas实际项目操作,包含:线条,圆形,扇形,图片绘制,图片圆角遮罩,矩形,弧形文字...
  • codis proxy处理流程
  • java8-模拟hadoop
  • javascript 总结(常用工具类的封装)
  • JSONP原理
  • mongo索引构建
  • MySQL Access denied for user 'root'@'localhost' 解决方法
  • react-core-image-upload 一款轻量级图片上传裁剪插件
  • Ruby 2.x 源代码分析:扩展 概述
  • vue-loader 源码解析系列之 selector
  • 从地狱到天堂,Node 回调向 async/await 转变
  • 得到一个数组中任意X个元素的所有组合 即C(n,m)
  • 每天一个设计模式之命令模式
  • 前端代码风格自动化系列(二)之Commitlint
  • 扫描识别控件Dynamic Web TWAIN v12.2发布,改进SSL证书
  • 使用前端开发工具包WijmoJS - 创建自定义DropDownTree控件(包含源代码)
  • 小程序滚动组件,左边导航栏与右边内容联动效果实现
  • 在Unity中实现一个简单的消息管理器
  • ​用户画像从0到100的构建思路
  • ​云纳万物 · 数皆有言|2021 七牛云战略发布会启幕,邀您赴约
  • #Ubuntu(修改root信息)
  • $.type 怎么精确判断对象类型的 --(源码学习2)
  • (+3)1.3敏捷宣言与敏捷过程的特点
  • (a /b)*c的值
  • (附源码)springboot家庭财务分析系统 毕业设计641323
  • (含react-draggable库以及相关BUG如何解决)固定在左上方某盒子内(如按钮)添加可拖动功能,使用react hook语法实现
  • (免费领源码)Java#ssm#MySQL 创意商城03663-计算机毕业设计项目选题推荐
  • (强烈推荐)移动端音视频从零到上手(下)
  • (转) ns2/nam与nam实现相关的文件
  • .NET 8.0 中有哪些新的变化?
  • .NET DataGridView数据绑定说明
  • .Net Redis的秒杀Dome和异步执行
  • .Net各种迷惑命名解释
  • .net和jar包windows服务部署
  • []FET-430SIM508 研究日志 11.3.31
  • [20171102]视图v$session中process字段含义
  • [2024] 十大免费电脑数据恢复软件——轻松恢复电脑上已删除文件
  • [ArcPy百科]第三节: Geometry信息中的空间参考解析