題意:農夫John的養牛場,是一個R 行C 列的矩形,一場大雨後,養牛場低洼的地方都有了積水。John 的牛都很嬌貴的,他們吃草的時候,不想把他們的蹄子給弄髒了。為了不讓牛兒們把它們的蹄子弄髒,John 決定把有水的地方鋪上木板。他的木板是寬度為1,長度沒有限制的。
他想用最少數目的木板把所有有水的低洼處給覆蓋上,前提是木板不能覆蓋草地,但是可以重疊。
這道題,構圖確實比比較巧妙,如果有連續的低洼處,假設是橫排的,那麼這幾個連續的低洼處可以拿一個板子來覆蓋,同樣,如果豎排也有連續的低洼處,那麼也可以拿一個板子來覆蓋。這樣,當一個低洼處既可以拿橫著的板子,也可以拿豎著的板子覆蓋時,就是相交了。那麼這個交線就代表了一個低洼處,它既可以被橫著蓋,也可以被豎著蓋。現在我們把所有橫排的低洼處作為left(連續的低洼處作為1個板),豎著的也同理,以例題如下表式:
Sample:
4 4
*.*.
.***
***.
..*.
把行裡面連在一起的坑連起來視為一個點,即一塊橫木板,編上序號,Sample則轉化為:
1 0 2 0
0 3 3 3
4 4 4 0
0 0 5 0
把這些序號加入X集合,再按列做一次則為:
1 0 4 0
0 3 4 5
2 3 4 0
0 0 4 0
同樣加入Y集合,一個坑只能被橫著的或者被豎著的木板蓋住,將原圖的坑的也標上不同的序號,一共九個坑
1 . 2 .
. 3 4 5
6 7 8 .
. . 9 .
圖中的2號低洼處既可以拿橫著的2號板,也可以拿豎著的4號板來覆蓋,那麼2號版和四號板之間就有一條邊,邊實際表示了低洼處,例如2號低洼處的邊為{2,4},可以理解為2號低洼處可以由2號板或4號板覆蓋。用最少的點把所有的邊連起來,這樣就是最小點覆蓋。
以上來自 http://hi.baidu.com/onlys_c/blog/item/9781e0dd858f2fd28d102919.html
#include <cstring>#include <iostream>using namespace std;char temp[100][100];bool map[1000][1000],vis[1000];int U[100][100], V[100][100],match[1000];int R,C,u,v;bool find_path ( int r ){for ( int i = 1; i <= v; i++ ){if ( map[r][i] && !vis[i] ){vis[i] = true;if ( 0 == match[i] || find_path(match[i]) ){match[i] = r;return true;}}}return false;}int Hungary(){int ans = 0;for ( int i = 1; i <= u; i++ ){memset(vis,0,sizeof(vis));if ( find_path ( i ) )ans++;}return ans;}void construct (){int i,j;memset(map,0,sizeof(map));memset(match,0,sizeof(match)); u = v = 0;for ( i = 1; i <= R; i++ )for ( j = 1; j <= C; j++ )cin >> temp[i][j];for ( i = 1; i <= R; i++ ){for ( j = 1; j <= C; j++ ){if ( temp[i][j] == '*' ){u++;while ( j <= C && temp[i][j] == '*' ){U[i][j] = u;j++;}}}}for ( j = 1; j <= C; j++ ){for ( i = 1; i <= R; i++ ){if ( temp[i][j] == '*' ){v++;while ( i <= R && temp[i][j] == '*' ){V[i][j] = v;i++;}}}}for ( i = 1; i <= R; i++ ){for ( j = 1; j <= C; j++ ){if ( temp[i][j] == '*' )map[U[i][j]][V[i][j]] = true;}}}int main(){cin >> R >> C;construct();cout << Hungary() << endl;return 0;}