题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5093
题目是给你一个n*m的图,图中有三种字符,*表示海洋,#表示冰山,o表示浮冰。浮冰和冰山不能放战舰,每一行一列只能放一艘战舰,除非两个战舰中间有冰山,问最多能放多少艘战舰?
这题和放炮台那个题类似(炮台:http://acm.hdu.edu.cn/showproblem.php?pid=1045)不过,那个题数据最大是4*4,而这个是50*50,炮台那个直接dfs一阵瞎搞,就过了,毕竟数据小,而这个就虚了。那晚上组队选ecfinal名额,看到这道题第一眼,就想瞎dfs肯定tle,应该是二分图匹配,之前刷贪心小练也遇到过炮台那道,不过没贪心,直接老套路dfs过,包括当初刷二分图匹配也是老套路dfs过,结果比赛遇到这个题,wr用贪心写过炮台,本来想这两道差不多,直接让他贪心写一发赶紧过,省的被别人追上,结果贪心贪了半个小时,交了一发wa,就懵逼了,lyq也追上我们了,唉,ecfinal也去不了了,~~(>_<)~~,还是怪自己懒,当初写那道炮台的时候不学二分匹配。。。
二分匹配建图,考虑到每一排#的两边不能都有*,所以遇到#可以将#后面的重新另起一行,列也是如此,这样就避免了冰山的阻挡,列同样也是如此。这样建图就好了~
代码:
#include<cstdio>
#include<cstring>
#include<string>
#include<queue>
#include<cmath>
#include<map>
#include<stack>
#include<iostream>
#include<algorithm>
using namespace std;
#define ll long long
#define inf 0x3f3f3f3f
const int spot=1300+10;
const int edge=2500+10;
const int maxn=50+10;
const double pi=acos(-1.0);nage1
int col[spot][spot],row[spot][spot],head[spot],sizes=0,marry[edge];
bool b[edge];
char graph[maxn][maxn];
struct stu
{
int to,next;
} a[edge];
void init() //初始化
{
sizes=0;
memset(head,-1,sizeof(head));
memset(marry,0,sizeof(marry));
}
void add_edge(int from,int to) //邻接表
{
a[sizes].to=to;
a[sizes].next=head[from];
head[from]=sizes++;
}
bool dfs(int u)
{
int k,v;
for(k=head[u]; k+1; k=a[k].next)
{
v=a[k].to;
if(!b[v])
{
b[v]=1;
if(!marry[v]||dfs(marry[v]))
{
marry[v]=u;
return 1;
}
}
}
return 0;
}
int max_match(int n) //匈牙利
{
int ans=0,i;
for(i=1; i<=n; i++)
{
memset(b,0,sizeof(b));
ans+=dfs(i);
}
return ans;
}
int main()
{
int nn,i,j;
scanf("%d",&nn);
while(nn--)
{
int n,m;
init();
scanf("%d%d",&n,&m);
for(i=1; i<=n; i++)
{
for(j=1; j<=m; j++)
cin>>graph[i][j];
}
int rownum=1,colnum=1;
for(i=1; i<=n; i++,rownum++)//对行处理
for(j=1; j<=m; j++)
{
if(graph[i][j]=='#'&&graph[i][j+1]!='#'&&j+1<=m)
rownum++;
row[i][j]=rownum;
}
for(j=1; j<=m; j++,colnum++) //对列处理
for(i=1; i<=n; i++)
{
if(graph[i][j]=='#'&&graph[i+1][j]!='#'&&i+1<=n)
colnum++;
col[i][j]=colnum;
}
for(i=1; i<=n; i++)
for(j=1; j<=m; j++)
if(graph[i][j]=='*')
add_edge(row[i][j],col[i][j]); //建边
printf("%d\n",max_match(rownum));
}
return 0;
}