poj 2226 Muddy Fields

Muddy Fields
Time Limit: 1000MS   Memory Limit: 65536K
Total Submissions: 10807   Accepted: 4015

Description

Rain has pummeled the cows' field, a rectangular grid of R rows and C columns (1 <= R <= 50, 1 <= C <= 50). While good for the grass, the rain makes some patches of bare earth quite muddy. The cows, being meticulous grazers, don't want to get their hooves dirty while they eat. 

To prevent those muddy hooves, Farmer John will place a number of wooden boards over the muddy parts of the cows' field. Each of the boards is 1 unit wide, and can be any length long. Each board must be aligned parallel to one of the sides of the field. 

Farmer John wishes to minimize the number of boards needed to cover the muddy spots, some of which might require more than one board to cover. The boards may not cover any grass and deprive the cows of grazing area but they can overlap each other. 

Compute the minimum number of boards FJ requires to cover all the mud in the field.

Input

* Line 1: Two space-separated integers: R and C 

* Lines 2..R+1: Each line contains a string of C characters, with '*' representing a muddy patch, and '.' representing a grassy patch. No spaces are present.

Output

* Line 1: A single integer representing the number of boards FJ needs.

Sample Input

4 4
*.*.
.***
***.
..*.

Sample Output

4

Hint

OUTPUT DETAILS: 

Boards 1, 2, 3 and 4 are placed as follows: 
1.2. 
.333 
444. 
..2. 
Board 2 overlaps boards 3 and 4.
 
题意:下雨之后农场某些土地泥泞了,牛不喜欢吃泥泞的草,约翰准备将这些泥泞的土地用宽度为1,长度不限的木板覆盖起来(木板只能平行于农场的长或宽来放置),问至少需要多少木板才可以把所有泥泞的土地都覆盖。
思路:对于土地上每一个‘*’,找找横向需要哪块木板去覆盖,竖向又需要那块木板来覆盖。
以题目为例:全是横向木板的放法:1 0 2 0数字是木板的编号,譬如‘333’就是一块木板,全是竖向木板:1 0 4 0
                                                        0 3 3 3                                                                                               0 3 4 5
                                                        4 4 4 0                                                                                               2 3 4 0
                                                        0 0 5 0                                                                                               0 0 4 0
那么譬如第一行第二个‘*’的位置如果用横向木板,就用横向第二块木板来覆盖,或者竖向第4块来覆盖。即可连接这两块木板,如此操作可构成二分图,图中两边的点代表横向竖向的木板,连边则代表一块泥泞的‘*’,对于每一条边而言我们至少要取到这条边的其中一个顶点,并且要使得取到的这个顶点集合尽量的小,就是求最小顶点覆盖。
AC代码:
#define _CRT_SECURE_NO_DEPRECATE
#include<iostream>
#include<algorithm>
#include<queue>
#include<set>
#include<vector>
#include<cstring>
#include<string>
using namespace std;
#define INF 0x3f3f3f3f
const int N_MAX = 2500+100,R_MAX=50+5;
int V;//点的个数
vector<int>G[N_MAX];
int match[N_MAX];
bool used[N_MAX];
void add_edge(int u, int v) {
    G[u].push_back(v);
    G[v].push_back(u);
}

bool dfs(int v) {
    used[v] = true;
    for (int i = 0; i < G[v].size(); i++) {
        int u = G[v][i], w = match[u];
        if (w < 0 || !used[w] && dfs(w)) {
            match[v] = u;
            match[u] = v;
            return true;
        }
    }
    return false;
}

int bipartite_matching() {
    int res = 0;
    memset(match, -1, sizeof(match));
    for (int v = 0; v < V; v++) {
        if (match[v] < 0) {
            memset(used, 0, sizeof(used));
            if (dfs(v))
                res++;
        }
    }
    return res;
}
char field[N_MAX][N_MAX];
int mark_x[N_MAX][N_MAX],mark_y[N_MAX][N_MAX];

int R, C;
int main() {
    while (scanf("%d%d",&R,&C)!=EOF) {
        memset(mark_x, -1, sizeof(mark_x));
        memset(mark_y, -1, sizeof(mark_y));
        for (int i = 0; i < R; i++){
                char c;
                scanf("%s",field[i]);
            }
        int num = 0; bool flag = 0,New=0;
        for (int i = 0; i < R;i++) {
            for (int j = 0; j < C;j++) {
                if (field[i][j] == '*') {
                    num++;
                    while (j<C&&field[i][j]=='*') {
                        mark_x[i][j] = num;
                        j++;
                    }
                }
            }
        }


         num = 0,flag=0, New = 0;
         for (int i = 0; i < C; i++) {
             for (int j = 0; j < R; j++) {
                 if (field[j][i] == '*') {
                     num++;
                     while (j<R&&field[j][i] == '*') {
                         mark_y[j][i] = num;
                         j++;
                     }
                 }
             }
         }


        V =N_MAX;
        //1~N_MAX/2:横向木板
        //N_MAX/2+1~N_MAX:纵向木板
        for (int i = 0; i < R; i++) {
            for (int j = 0; j < C; j++) {
                if (field[i][j] == '*') {
                    add_edge(mark_x[i][j],mark_y[i][j]+N_MAX/2);
                }
            }
    }

        printf("%d
",bipartite_matching());
        for (int i = 0; i < V;i++) {
            G[i].clear();
        }
    }
    return 0;
}
原文地址:https://www.cnblogs.com/ZefengYao/p/7266919.html