题意:一个m*n的海域,你需要在上面安排尽可能多的战船。地图上有普通海域(*),冰山(#),浮冰(o),安排战船需要遵守的规则是,只能在普通海域放置战船,每一行只能有一艘串,每一列只能有一艘船,如果一行/列被冰山阻隔,则可视为多行/列。
思路:二分图匹配,行作为一个集合,列作为另一个集合。首先扫描一遍地图,为每个地点分配一个行号和列号,就可以建图跑最大流了。
#include<cstdio>
#include<iostream>
#include<queue>
#include<algorithm>
#include<string.h>
#include<string>
using namespace std;
#define maxn 1260
#define INF 1000000000
char mp[55][55];
int ss[55][55];
int tt[55][55];
int m,n;
int cnts,cntt;
struct Edge{
int u; int v;
int cap; int flow;
Edge(int u,int v,int c):u(u),v(v),cap(c),flow(0){}
Edge(){};
};
Edge edges[maxn*maxn];
int ne;
int head[maxn];
int next[maxn*maxn];
void init(){
memset(head,-1,sizeof(head));
ne=0;
}
int lv[maxn];
bool bfs(int s,int t){
memset(lv,-1,sizeof(lv)); lv[s]=0;
queue<int> que; que.push(s);
while(!que.empty()){
int cur=que.front(); que.pop();
for(int i=head[cur];i!=-1;i=next[i]){
Edge& e=edges[i];
if(lv[e.v]!=-1)continue;
if(e.flow<e.cap){
lv[e.v]=lv[cur]+1;
que.push(e.v);
}
}
if(lv[t]!=-1)return 1;
}
return 0;
}
int cur[maxn];
int dfs(int x,int a){
if(x==cnts+cntt+1||a==0)return a;
int re=0;
for(int& i=cur[x];i!=-1;i=next[i]){
Edge& e=edges[i];
int t;
if(lv[e.v]==(lv[x]+1)&& (t=dfs( e.v , min(a,e.cap-e.flow))) ){
edges[i].flow+=t;
edges[i^1].flow-=t;
re+=t;
a-=t;
if(a==0)break;
}
}
return re;
}
int maxflow(int s,int t){
int flow=0;
while(bfs(s,t)){
memcpy(cur,head,sizeof(head));
flow+=dfs(s,INF);
}
return flow;
}
void addedge(int u,int v,int c){
edges[ne]=Edge(u,v,c);
next[ne]=head[u];
head[u]=ne;
ne++;
edges[ne]=Edge(v,u,0);
next[ne]=head[v];
head[v]=ne;
ne++;
}
int main(){
int t;
cin>>t;
while(t--){
init();
cin>>m>>n;
for(int i=1;i<=m;i++){
scanf("%s",mp[i]+1);
}
cnts=0;
cntt=0;
//横向
for(int i=1;i<=m;i++){
for(int j=1;j<=n;j++){
if(mp[i][j]!='#')cnts++;
while(mp[i][j]!='#'){
ss[i][j]=cnts;
j++;
if(j>n)break;
}
}
}
//纵向
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(mp[j][i]!='#')cntt++;
while(mp[j][i]!='#'){
tt[j][i]=cntt;
j++;
if(j>m)break;
}
}
}
for(int i=1;i<=cnts;i++){
addedge(0,i,1);
}
for(int i=cnts+1;i<=cnts+cntt;i++){
addedge(i,cnts+cntt+1,1);
}
//建图
for(int i=1;i<=m;i++){
for(int j=1;j<=n;j++){
if(mp[i][j]=='*'){
addedge(ss[i][j],cnts+tt[i][j],1);
}
}
}
int ans=maxflow(0,cnts+cntt+1);
cout<<ans<<endl;
}
return 0;
}