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

洛谷:P6062 [USACO05JAN]Muddy Fields G

题目链接:P6062 [USACO05JAN]Muddy Fields G - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

此题重点在二分图的建图。

考虑放置木板的决策,由于可以重复覆盖,所以对于两个可以选择的区间 a,b,若 b 被 a 覆盖,那么选择 a 一定优于选择 b。

解释如图:泥地为黄色,草地为绿色

显然,木板 A 一定比木板 B 更优,因为橙色部分可以重复覆盖。

由此易得所有的木板两头都是没有泥地的:若有,则增长此木板一定比原方案更优。

得到这个结论,我们可以先预处理出所有可能放置木板的位置,也就是在每行每列连续的泥地的位置。如图所示:所有木板可能放置的位置是下图的十个。

        

对于每一个点,要么被横着覆盖,要么被竖着覆盖。举例来讲,(3,3)在行上会被横木板 3 覆盖,在列上会被竖木板 4 覆盖。而我们要让所有的点都被覆盖,也就是需要满足下图所示的所有条件:

        

我们需要选出最少的木板满足这样的若干个约束条件。我们把每一个泥地看成一条边,左端点为其对应的横木板,右端点为其对应的竖木板。 显然这是一个二分图,左边全部为横木板,右边全部为竖木板。

        

考虑我们放置一个木板,相当于满足所有包含它的约束条件,也就是将其所连的边进行染色。 而对于每一个泥地(也就是边),如果它被染色,就证明这个格子的约束条件已被满足

所以这个问题转化为:一次操作可以选择一个点,将所连的边染色,目的是让所有边被染色。

即为二分图最小点覆盖。

而最小点覆盖等于最大匹配,故建图跑匈牙利即可。

#include <cstdio>
#include <cstring>
#include <iostream>

using namespace std;

const int N = 55 * 55;

int n, m;
bool st[N];
int match[N];
bool con[N][N];
char str[N][N];
int row[N][N], col[N][N];
int row_cnt, col_cnt;

bool find(int a)
{
    for (int b = 1; b <= col_cnt; b ++ )
    {
        if (!con[a][b]) continue;
        if (st[b]) continue;
        st[b] = true;
        
        if (match[b] == -1 || find(match[b]))
        {
            match[b] = a;
            return true;
        }
    }
    
    return false;
}

int main()
{
    cin >> n >> m;
    memset(match, -1, sizeof match);
    for (int i = 1; i <= n; i ++ ) cin >> str[i] + 1;
    
    for (int i = 1; i <= n; i ++ )//按行枚举找木板数
        for (int j = 1; j <= m; j ++ )
            if (str[i][j] == '*')
                if (j == 1 || str[i][j - 1] != '*') row[i][j] = ++ row_cnt ;
                else row[i][j] = row_cnt;
    
    for (int i = 1; i <= m; i ++ )//按列枚举找木板数
        for (int j = 1; j <= n; j ++ )
            if (str[j][i] == '*')
                if (j == 1 || str[j - 1][i] != '*') col[j][i] = ++ col_cnt;
                else col[j][i] = col_cnt;
    
    for (int i = 1; i <= n; i ++ )//建图
        for (int j = 1; j <= m; j ++ ) con[row[i][j]][col[i][j]] = true;
    
    int res = 0;
    for (int i = 1; i <= row_cnt; i ++ )//最小点覆盖 = 最大匹配数
    {
        memset(st, false, sizeof st);
        if (find(i)) res ++ ;
    }
    
    cout << res << endl;
    
    return 0;
}

相关文章:

  • 七、手把手教你搭建SpringCloudAlibaba之Sentinel实现流量控制
  • vue3 创建vue3模板
  • js 导出 excel
  • Mybatis-Plus(核心功能篇 ==> 代码生成器(新版)
  • Intel汇编-LOOP循环检查ECX含零值
  • DBNet学习笔记
  • 1、搭建环境
  • 基于Java+Spring+vue+element社区疫情服务平台设计和实现
  • 【Leetcode】剑指Offer 34:二叉树中和为某一值的路径
  • CockroachDB架构-复制层
  • Netty 入门学习(1)
  • Android手部检测和手势识别(含训练代码+Android源码+手势识别数据集)
  • 【NLP】第4章 从头开始预训练 RoBERTa 模型
  • 第3章 循环神经网络
  • 机器学习入门八
  • [rust! #004] [译] Rust 的内置 Traits, 使用场景, 方式, 和原因
  • [Vue CLI 3] 配置解析之 css.extract
  • 2017 前端面试准备 - 收藏集 - 掘金
  • chrome扩展demo1-小时钟
  • CSS相对定位
  • Iterator 和 for...of 循环
  • JS基础篇--通过JS生成由字母与数字组合的随机字符串
  • LeetCode18.四数之和 JavaScript
  • Linux链接文件
  • MySQL的数据类型
  • Netty源码解析1-Buffer
  • nfs客户端进程变D,延伸linux的lock
  • Octave 入门
  • SpiderData 2019年2月23日 DApp数据排行榜
  • SpringBoot 实战 (三) | 配置文件详解
  • Vue组件定义
  • 阿里云前端周刊 - 第 26 期
  • 浮现式设计
  • 规范化安全开发 KOA 手脚架
  • 基于Dubbo+ZooKeeper的分布式服务的实现
  • 利用DataURL技术在网页上显示图片
  • 如何将自己的网站分享到QQ空间,微信,微博等等
  • 如何使用 OAuth 2.0 将 LinkedIn 集成入 iOS 应用
  • ionic异常记录
  • mysql面试题分组并合并列
  • zabbix3.2监控linux磁盘IO
  • 湖北分布式智能数据采集方法有哪些?
  • ​直流电和交流电有什么区别为什么这个时候又要变成直流电呢?交流转换到直流(整流器)直流变交流(逆变器)​
  • # 日期待t_最值得等的SUV奥迪Q9:空间比MPV还大,或搭4.0T,香
  • #LLM入门|Prompt#3.3_存储_Memory
  • (4.10~4.16)
  • (MonoGame从入门到放弃-1) MonoGame环境搭建
  • (react踩过的坑)antd 如何同时获取一个select 的value和 label值
  • (TipsTricks)用客户端模板精简JavaScript代码
  • (附源码)springboot猪场管理系统 毕业设计 160901
  • (删)Java线程同步实现一:synchronzied和wait()/notify()
  • (循环依赖问题)学习spring的第九天
  • (一)kafka实战——kafka源码编译启动
  • (转) Android中ViewStub组件使用
  • (转) SpringBoot:使用spring-boot-devtools进行热部署以及不生效的问题解决