D178 二分图最小点覆盖 匈牙利算法 P6062 [USACO05JAN] Muddy Fields G

D178 二分图最小点覆盖 匈牙利算法 P6062 [USACO05JAN] Muddy Fields G_哔哩哔哩_bilibili

 

P6062 [USACO05JAN] Muddy Fields G - 洛谷

牧场是一个 R×C 的矩形,其中 1R,C50。每块木板的宽度为 1 个单位,长度任意,每个板必须放置在平行于牧场的泥地里。

求使用最少的木板覆盖所有的泥地。一个木板可以重叠在另一个木板上,但是不能放在草地上。

思路

根据贪心思想,给连续泥地放一块木板,即连续泥地的坐标使用相同的木板编号

木板分两类:横放的、竖放的,横放的木板编号看做左部点,竖放的木板编号看做右部点,对重叠木板编号从左向右连边

题目就是选出最少的端点(木板),覆盖所有的边,即最小点覆盖,这样,每块泥地都被一块或两块木板盖住

参考:D177 二分图最小点覆盖 匈牙利算法 U455932 机器任务 - 董晓 - 博客园

 

// 二分图 匈牙利算法 O(V*E)
#include<bits/stdc++.h>
using namespace std;

const int N=1255;
vector<int> e[N];
int n,m,sx,sy,ans;
char a[55][55];
int x[55][55],y[55][55];
int vis[N],match[N];

bool dfs(int u){
  for(auto v:e[u]){ //竖向编号是右部点
    if(vis[v]) continue; //v已参与
    vis[v]=1; //记录v参与
    if(!match[v]||dfs(match[v])){ //v没配对或v的男友可退让
      match[v]=u; //记录v的男友u
      return 1; //配对成功
    }
  }
  return 0; //配对失败
}
int main(){
  cin>>n>>m;
  for(int i=1;i<=n;++i){
    cin>>a[i]+1; //输入一行字符
    for(int j=1;j<=m;++j){
      if(a[i][j]=='*'){
        x[i][j]=(a[i][j-1]=='*'?x[i][j-1]:++sx); //横向木板编号
        y[i][j]=(a[i-1][j]=='*'?y[i-1][j]:++sy); //竖向木板编号
        e[x[i][j]].push_back(y[i][j]); //木板横向编号→竖向编号连边
      }
    }
  }
    
  for(int i=1;i<=sx;i++){ //横向编号是左部点
    memset(vis,0,sizeof vis);
    ans+=dfs(i); //累加配对数
  }
  cout<<ans;
  return 0;
}

 

posted @ 2026-05-31 18:44  董晓  阅读(36)  评论(0)    收藏  举报