[題解] [USACO05JAN]Muddy Fields G
阿新 • • 發佈:2020-12-02
題目大意
在一個 \(R×C\) 的矩陣中,每個點有兩個狀態:草地和泥地。你需要在泥地裡鋪 \(1×k\) 木塊, \(k\) 為任意整數,求最少要多少木塊。
思路
兩個橫向木塊不會互相干擾,兩個豎向木塊不會互相干擾,且一個點的覆蓋方法只有橫向木塊覆蓋與豎向木塊兩種覆蓋方法,不難想到二分圖的最小點覆蓋。
設每個點 \(i\) 的豎向木板的編號為 \(belong1[i]\) ,橫向木板的編號為 \(belong2[i]\) ,則這個點可能會被 \(belong1[i]\) 與 \(belong2[i]\) 任意一個所覆蓋,所以將 \(belong1[i]\) 與 \(belong2[i]\)
最後在求出最小點覆蓋,就是最少需要木板的個數。
C++程式碼
#include <cstdio> #include <vector> #include <cstring> using namespace std; void Quick_Read(int &N) { N = 0; int op = 1; char c = getchar(); while(c < '0' || c > '9') { if(c == '-') op = -1; c = getchar(); } while(c >= '0' && c <= '9') { N = (N << 1) + (N << 3) + (c ^ 48); c = getchar(); } N *= op; } const int MAXN = 5e3 + 5; const int MAXM = 55; vector<int> v[MAXN]; int belong1[MAXM][MAXM], belong2[MAXM][MAXM]; char Mp[MAXM][MAXM]; int twin[MAXN]; bool vis[MAXN]; int r, c, n, m; bool Hungary(int now) {//匈牙利演算法 int SIZ = v[now].size(); for(int i = 0; i < SIZ; i++) { int next = v[now][i]; if(!vis[next]) { vis[next] = true; if(!twin[next] || Hungary(twin[next])) { twin[next] = now; return true; } } } return false; } int Match() {//匹配 int res = 0; for(int i = 1; i <= n; i++) { memset(vis, 0, sizeof(vis)); if(Hungary(i)) res++; } return res;//二分圖中最小點覆蓋就等於最大匹配 } void Build() { n = 1; for(int i = 1; i <= r; i++) {//求出橫向木板 bool last = false; for(int j = 1; j <= c; j++) { if(Mp[i][j] == '*') { belong1[i][j] = n; last = true; } else { if(last) n++; last = false; } } if(last) n++; } m = n + 1; n--; for(int j = 1; j <= c; j++) {//求出豎向模板 bool last = false; for(int i = 1; i <= r; i++) { if(Mp[i][j] == '*') { belong2[i][j] = m; last = true; } else { if(last) m++; last = false; } } if(last) m++; } for(int i = 1; i <= r; i++) for(int j = 1; j <= c; j++) if(Mp[i][j] == '*') v[belong1[i][j]].push_back(belong2[i][j]);//建圖 } void Read() { Quick_Read(r); Quick_Read(c); for(int i = 1; i <= r; i++) scanf("%s", Mp[i] + 1); } int main() { Read(); Build(); printf("%d", Match()); return 0; }