Oil Skimming
Problem Description
Thanks to a certain “green” resources company, there is a new profitable industry of oil skimming. There are large slicks of crude oil floating in the Gulf of Mexico just waiting to be scooped up by enterprising oil barons. One such oil baron has a special plane that can skim the surface of the water collecting oil on the water’s surface. However, each scoop covers a 10m by 20m rectangle (going either east/west or north/south). It also requires that the rectangle be completely covered in oil, otherwise the product is contaminated by pure ocean water and thus unprofitable! Given a map of an oil slick, the oil baron would like you to compute the maximum number of scoops that may be extracted. The map is an NxN grid where each cell represents a 10m square of water, and each cell is marked as either being covered in oil or pure water.
Input
The input starts with an integer K (1 <= K <= 100) indicating the number of cases. Each case starts with an integer N (1 <= N <= 600) indicating the size of the square grid. Each of the following N lines contains N characters that represent the cells of a row in the grid. A character of ‘#’ represents an oily cell, and a character of ‘.’ represents a pure water cell.
Output
For each case, one line should be produced, formatted exactly as follows: “Case X: M” where X is the case number (starting from 1) and M is the maximum number of scoops of oil that may be extracted.
Sample Input
1
6
…
.##…
.##…
…#.
…##
…
Sample Output
Case 1: 3
题意:在大海里分布着一些石油(‘#’代表石油),现在只能回收1*2大小的石油块,求最多能回收多少。
思路:可以把‘#’看成一些独立的点,如果在它的旁边出现了’#‘,就把它们连边,然后就只需要求最多的匹配边就行了,因为一个点的左右或者上下可能会同时出现另一个点,他们都会连边,所以最后要对求出来的最大匹配除以2。
#include<cstdio>
#include<cstring>
#include<cmath>
#include<vector>
#include<queue>
#include<iostream>
#include<algorithm>
using namespace std;
#define maxn 610
#define ll long long
#define inf 0x3f3f3f3f
#define mod 998244353
char mp[maxn][maxn];
int biao[maxn][maxn],vis[maxn],match[maxn];
int dic[4][2]= {0,1,1,0,-1,0,0,-1};
vector<int> v[maxn];
int n,Case=1;
int dfs(int u)
{
for(int i=0; i<v[u].size(); i++)
{
int k=v[u][i];
if(!vis[k])
{
vis[k]=1;
if(!match[k]||dfs(match[k]))
{
match[k]=u;
return 1;
}
}
}
return 0;
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
memset(biao,0,sizeof(biao));
memset(match,0,sizeof(match));
for(int i=0; i<maxn; i++)
v[i].clear();
int cnt=1;
scanf("%d",&n);
for(int i=0; i<n; i++)
{
for(int j=0; j<n; j++)
{
scanf(" %c",&mp[i][j]);
if(mp[i][j]=='#') biao[i][j]=cnt++; //因为要连边所以要先给所有的'#'标号
}
}
for(int i=0; i<n; i++)
{
for(int j=0; j<n; j++)
{
if(mp[i][j]=='#')
{
for(int q=0; q<4; q++) //寻找这个'#'的四周是否还有'#'出现
{
int dx=i+dic[q][0];
int dy=j+dic[q][1];
if(dx>=0&&dx<n&&dy>=0&&dy<n&&mp[dx][dy]=='#')
{
v[biao[i][j]].push_back(biao[dx][dy]); //把这两个'#'连边
}
}
}
}
}
int ans=0;
for(int i=1; i<=cnt; i++)
{
memset(vis,0,sizeof(vis));
if(dfs(i)) ans++;
}
printf("Case %d: %d\n",Case++,ans/2);
}
return 0;
}