二分图匹配
P6062 [USACO05JAN]Muddy Fields G
题目描述
大雨侵袭了奶牛们的牧场。
牧场是一个 R×C 的矩形,其中 1≤R,C≤50。大雨将没有长草的土地弄得泥泞不堪,可是小心的奶牛们不想在吃草的时候弄脏她们的蹄子。为了防止她们的蹄子被弄脏,约翰决定在泥泞的牧场里放置一些木板。每一块木板的宽度为 1 个单位,长度任意,每一个板必须放置在平行于牧场的泥地里。
约翰想使用最少的木板覆盖所有的泥地.一个木板可以重叠在另一个木板上,但是不能放在草地上。
输入格式
第一行两个整数 R,C。
接下来 R 行,每行 C 个字符,描述牧场,其中 * 为泥地,. 为草地。
输出格式
输出一个整数,最少需要多少木板。
输入
4 4
..
.***
**.
...
输出
4
思路
我们把每个位置的行列抽象出来就可以了。
此题重点在二分图的建图。
考虑放置木板的决策,由于可以重复覆盖,所以对于两个可以选择的区间 a,ba,b,若 bb 被 aa 覆盖,那么选择 aa 一定优于选择 bb。
解释如图:泥地为黄色,草地为绿色
显然,木板 AA 一定比木板 BB 更优,因为橙色部分可以重复覆盖。
由此易得所有的木板两头都是没有泥地的:若有,则增长此木板一定比原方案更优。
得到这个结论,我们可以先预处理出所有可能放置木板的位置,也就是在每行每列连续的泥地的位置。如图所示:所有木板可能放置的位置是下图的十个。
对于每一个点,要么被横着覆盖,要么被竖着覆盖。举例来讲,(3,3)(3,3) 在行上会被横木板 33 覆盖,在列上会被竖木板 44 覆盖。而我们要让所有的点都被覆盖,也就是需要满足下图所示的所有条件:
我们需要选出最少的木板满足这样的若干个约束条件。我们把每一个泥地看成一条边,左端点为其对应的横木板,右端点为其对应的竖木板。 显然这是一个二分图,左边全部为横木板,右边全部为竖木板。
考虑我们放置一个木板,相当于满足所有包含它的约束条件,也就是将其所连的边进行染色。 而对于每一个泥地(也就是边),如果它被染色,就证明这个格子的约束条件已被满足。
所以这个问题转化为:一次操作可以选择一个点,将所连的边染色,目的是让所有边被染色。
即为二分图最小点覆盖。
而最小点覆盖等于最大匹配,故建图跑匈牙利即可。
#include <bits/stdc++.h>
#define LL long long
using namespace std;
struct Edge{
int to, nxt;
}E[100005];
int head[1000005], cut=0;
struct Hyl{
int now=0, girl[1000005], used[1000005];
void Add(int x, int y){
//cout<<x<<"->"<<y<<endl;
E[++cut]={y, head[x]}; head[x]=cut;
}
int dfs(int u){
for(int i=head[u]; i; i=E[i].nxt){
int to=E[i].to;
if(used[to]==now) continue;
used[to]=now;
if(!girl[to]||dfs(girl[to])){
girl[to]=u; return 1;
}
}
return 0;
}
int work(int n){
int res=0;
for(int i=1; i<=n; i++){
now=i;
res+=dfs(i);
}
return res;
}
}T;
char a[1005][1005];
int idx[1005][1005];
int idy[1005][1005];
int main() {
int n, m; scanf("%d%d", &n, &m);
for(int i=1; i<=n; i++){
scanf("%s", a[i]+1);
}
int x=1;
for(int i=1; i<=n; i++){
for(int j=1; j<=m; j++){
if(a[i][j]=='.') x++;
idx[i][j]=x;
}
x++;
}
int y=1;
for(int j=1; j<=m; j++){
for(int i=1; i<=n; i++){
if(a[i][j]=='.') y++;
idy[i][j]=y;
}
y++;
}
for(int i=1; i<=n; i++){
for(int j=1; j<=m; j++){
if(a[i][j]=='*'){
T.Add(idx[i][j], idy[i][j]);
}
}
}
printf("%d\n", T.work(x));
return 0;
}
P2825 [HEOI2016/TJOI2016]游戏
P2825 [HEOI2016/TJOI2016]游戏(https://www.luogu.com.cn/problem/P2825)
题目描述
在 2016 年,佳媛姐姐喜欢上了一款游戏,叫做泡泡堂。
简单的说,这个游戏就是在一张地图上放上若干个炸弹,看是否能炸到对手,或者躲开对手的炸弹。在玩游戏的过程中,小 H 想到了这样一个问题:当给定一张地图,在这张地图上最多能放上多少个炸弹能使得任意两个炸弹之间不会互相炸到。炸弹能炸到的范围是该炸弹所在的一行和一列,炸弹的威力可以穿透软石头,但是不能穿透硬石头。
给定一张 n×m 的网格地图:其中 * 代表空地,炸弹的威力可以穿透,可以在空地上放置一枚炸弹。 x 代表软石头,炸弹的威力可以穿透,不能在此放置炸弹。# 代表硬石头,炸弹的威力是不能穿透的,不能在此放置炸弹。例如:给出 1×4 的网格地图 xx,这个地图上最多只能放置一个炸弹。给出另一个1×4 的网格地图 x#,这个地图最多能放置两个炸弹。
现在小 H 任意给出一张 n×m 的网格地图,问你最多能放置多少炸弹。
输入格式
第一行输入两个正整数 n, m, n 表示地图的行数,m 表示地图的列数。
接下来输入 n 行 m 列个字符,代表网格地图。*的个数不超过 n×m 个。
输出格式
输出一个整数 a,表示最多能放置炸弹的个数。
输入
4 4
***
#*
*#
xxx#
输出
5
说明/提示
1≤n,m≤50
思路
和上面一样把行列抽象。
把点抽象成边,任何就是最大匹配
#include <bits/stdc++.h>
#define LL long long
using namespace std;
struct Edge{
int to, nxt;
}E[100005];
int head[5500], cut=0;
struct Hyl{
int now=0, girl[5500], used[5500];
void Add(int x, int y){
//cout<<x<<"->"<<y<<endl;
E[++cut]={y, head[x]}; head[x]=cut;
}
int dfs(int u){
for(int i=head[u]; i; i=E[i].nxt){
int to=E[i].to;
if(used[to]==now) continue;
used[to]=now;
if(!girl[to]||dfs(girl[to])){
girl[to]=u; return 1;
}
}
return 0;
}
int work(int n){
int res=0;
for(int i=1; i<=n; i++){
now=i;
res+=dfs(i);
}
return res;
}
}T;
char a[55][55];
int idx[55][55];
int idy[55][55];
int main() {
int n, m; scanf("%d%d", &n, &m);
for(int i=1; i<=n; i++){
scanf("%s", a[i]+1);
}
int x=1;
for(int i=1; i<=n; i++){
for(int j=1; j<=m; j++){
if(a[i][j]=='#') x++;
idx[i][j]=x;
}
x++;
}
int y=1;
for(int j=1; j<=m; j++){
for(int i=1; i<=n; i++){
if(a[i][j]=='#') y++;
idy[i][j]=y;
}
y++;
}
for(int i=1; i<=n; i++){
for(int j=1; j<=m; j++){
if(a[i][j]=='*'){
T.Add(idx[i][j], idy[i][j]);
}
}
}
printf("%d\n", T.work(x));
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)