要用1×2的板子尽量多的覆盖##区域,且不能交叉,求至多可以覆盖多少板子。
每一个#向向下或向右相邻的#建边。求最大匹配就可以了。
其实这题数据是比较弱的把,应该是#的个数在600以内把。。
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <string>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <vector>
#include <queue>
#include <map>
#define inf 0x3f3f3f3f
#pragma comment(linker, "/STACK:16777216")
#define eps 1e-6
#define ll long long
using namespace std;
int n,cnt,mx[605],my[605],vis[605],e[605][605],mp[605][605];
char s[605][605];
int path(int i)
{
int j;
for(j=1;j<cnt;j++)
{
if(e[i][j]&&!vis[j])
{
vis[j]=1;
if(my[j]==-1||path(my[j]))
{
my[j]=i;
mx[i]=j;
return 1;
}
}
}
return 0;
}
int hungary()
{
int res=0;
memset(mx,-1,sizeof mx);
memset(my,-1,sizeof my);
for(int i=1;i<cnt;i++)
{
if(mx[i]==-1)
{
memset(vis,0,sizeof vis);
res+=path(i);
}
}
return res;
}
int main()
{
int icy,cas=1,i,j;
scanf("%d",&icy);
while(icy--)
{
scanf("%d",&n);
memset(e,0,sizeof e);
memset(mp,0,sizeof mp);
for(i=0;i<n;i++)
scanf("%s",s[i]);
cnt=1;
for(i=0;i<n;i++)
for(j=0;j<n;j++)
if(s[i][j]=='#')
mp[i][j]=cnt++;
for(i=0;i<n;i++)
for(j=0;j<n;j++)
{
if(mp[i][j])
{
if(i<n-1&&mp[i+1][j])
e[mp[i][j]][mp[i+1][j]]=e[mp[i+1][j]][mp[i][j]]=1;
if(j<n-1&&mp[i][j+1])
e[mp[i][j+1]][mp[i][j]]=e[mp[i][j]][mp[i][j+1]]=1;
}
}
memset(vis,0,sizeof vis);
int ans=hungary();
printf("Case %d: %d\n",cas++,ans/2);
}
return 0;
}