トピックリンク http://poj.org/problem?id=2226
効果の対象:
格子状の表面にN * Mは、格子のいくつかは、他の格子がきれいで、泥です。
今1の幅の使用を必要カバーが床をきれいにすることはできませんが、任意の泥の長さは、木材をカバーしています。
各ボードは、木材は重なることが、完全な格子の複数で覆われなければなりません。
どのくらいの木材は、最小需要が必要です。
入力形式
最初の行は二つの整数N及びMを含有します
Mシンボルの次のNライン、地面を記述するために使用され、「*」格子泥を表し、「」グリッドときれいな、文字の間にスペースがないことを意味します。
出力フォーマット
出力結果を表す整数。データ範囲1≤N、M≤50
アイデア:
最初の話の最小カバレッジはSが存在するセット内の2つの端縁が、少なくとも一つのポイントように、最小の点集合Sが最小カバレッジで、二部グラフのエッジのためのものです。次の2つの端辺のために、それは濃縮物または他の濃縮点に、すなわち任意であり、それを通して点に配置することができるという、より簡単に変更することができます。それは、あること、また、下に覆われた最も重要なシンボルである1は、少なくとも二つを満たすことができます。
タイトルとカバーの接触の最小値は非常に直感的ではありません。それが泥だらけである場合のポイントについては、間違いなくカバーボードに必要な、このボードは横に置くことができ、それは端にかもしれないが、限り、あなたはこの点をカバーするために置くことができますように、このポイントのプレートの横または縦に置くことです両方は、少なくともこの問題の最小カバレッジであると接しており、いずれかを選択して、プレートを置きます。我々は継続的に横と縦に連続泥泥だらけのブロックと呼ばれる行と列の通信ブロック通信する場合。その後、明らかに、両方泥ブロックの各点に属するは、図中の2つの端辺にマッピングされる列ブロックを通信する通信回線に属します。最小のカバレッジを見つけるために、すべての通信ブロックのランクを得ることが可能であり、図組み込み、通信ブロックの一の側に接続されたすべての通信ブロックの行と列泥ポイント。
//============================================================================
// Name : test.cpp
// Copyright : Your copyright notice
// Description : Hello World in C++, Ansi-style
//============================================================================
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#define mem(a, b) memset(a, b, sizeof a)
using namespace std;
const int N = 3e4;
int head[N], nex[N], to[N], cnt;
inline void add(int a, int b){
++cnt;
to[cnt] = b;
nex[cnt] = head[a];
head[a] = cnt;
}
int n, m;
char s[55][55];
int row[55][55], column[55][55];
int rows, columns;
int match[N];
bool vis[N];
void pre_work(){
cnt = 0;
mem(head, -1);
mem(nex, -1);
mem(match, -1);
rows = 1;
columns = 1;
for (int i = 1; i <= n; i++){
int j = 1;
while (j <= m){
while (j <= m && s[i][j] == '*'){
row[i][j] = rows;
j++;
}
++rows;
while (j <= m && s[i][j] != '*'){
j++;
}
}
}
for (int i = 1; i <= m; i++){
int j = 1;
while (j <= n){
while (j <= n && s[j][i] == '*'){
column[j][i] = columns;
++j;
}
++columns;
while (j <= n && s[j][i] != '*'){
++j;
}
}
}
for (int i = 1; i <= n; i++){
for (int j = 1; j <= m; j++){
if (s[i][j] == '*'){
add(row[i][j], column[i][j] + rows + 10);
add(column[i][j] + rows + 10, row[i][j]);
}
}
}
}
bool dfs(int x){
for (int i = head[x]; i != -1; i = nex[i]){
int y = to[i];
if (vis[y])continue;
vis[y] = 1;
if (match[y] == -1 || dfs(match[y])){
match[y] = x;
return 1;
}
}
return 0;
}
int main()
{
scanf("%d %d", &n, &m);
getchar();
for (int i = 1; i <= n; i++){
scanf("%s", s[i] + 1);
}
pre_work();
int ans = 0;
for (int i = 1; i < rows; i++){
mem(vis, 0);
if (dfs(i))++ans;
}
printf("%d\n", ans);
return 0;
}