HDU-4185 Oil Skimming(二分匹配,匈牙利算法)
题意:给出一个N*N图,#表示有油,.表示水。现在要统计最多有多少块符合条件的油田
条件:油田不能重合,为1 x 2 的矩形,可以竖着1x2也可以横着1x2。
思路:我们可以把所有的油田看作一个单独的块,匹配时就搜索当前块上下左右相邻是否有油田
实际上就是 油田作为一个点,两两相邻的点符合条件就连接一条边。然后用二分图的匹配形式去找到最大匹配
同时这种最大匹配实际上有重复(连成无相图了),所以最后还要除以2
完整代码:
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int maxm = 1e4; const int maxn = 1005; char G[maxn][maxn]; int bmap[maxn][maxn]; int cur[maxn][maxn]; int n; int cnt ; int match[maxn];//表示匹配关系(左集合到右集合的匹配) int vis[maxn];//表示是否被访问过 //记录匹配个数 bool Find(int u){ for(int i = 0;i<cnt;i++){ int v = i; if(!vis[v]&&bmap[u][v]){ vis[v] = 1; if(!match[v]||Find(match[v])){ match[v] = u; return true; } } } return false; } int hungary(){ int count = 0; memset(match,0,sizeof(match)); for(int i =0;i<cnt;i++){ memset(vis,0,sizeof(vis)); if(Find(i)) count++; } return count; } int main(){ int T; cin>>T; int cas = 0; while(T--){ memset(G,0,sizeof(G)); cnt = 0; cin>>n; for(int i =0;i<n;i++){ cin>>G[i]; } for(int i =0 ;i<n;i++){ for(int j =0;j<n;j++){ if(G[i][j]=='#') cur[i][j] = cnt++; } } memset(bmap,0,sizeof(bmap)); for(int i =0;i<n;i++){ for(int j = 0;j<n;j++){ if(G[i][j]!='#') continue; if(i>0&&G[i-1][j]=='#') bmap[cur[i][j]][cur[i-1][j]] = 1; if(i<n-1&&G[i+1][j]=='#') bmap[cur[i][j]][cur[i+1][j]] = 1; if(j>0&&G[i][j-1]=='#') bmap[cur[i][j]][cur[i][j-1]] = 1; if(j<n-1&&G[i][j+1]=='#') bmap[cur[i][j]][cur[i][j+1]] = 1; } } int num = hungary(); cout<<"Case "<<++cas<<": "<<num/2<<endl; } }