题目:Battle Ships
题意:给一个由‘#’,‘*’,‘o’三种字符组成的矩阵,要求选择一些‘*’来摆战舰,同一行或同一列的战舰如果中间没有‘#’隔开是会互相攻击的,所以没有‘#’隔开时不能同时放,‘o’上不能摆放,要求最多摆多少战舰。
将所有行拿出来重新编号,对于被‘#’隔成多行的,可以看做多行,设置一个源点,每个行看作一个点,源点到这些点都连一条边,流量为1。表示这些行可以放置一个。
同样道理取出所有列,设置一个汇点,每个列对应的点连一条流量为1的边到汇点,表示这些列可以放置一个。
然后对于所有的‘*’,找出它们对应的行和列,从行到列连一条边,表示在对应的行和列放置一个。
最后求一下最大流就是答案。
PS:也可以直接根据行和列构建二部图求最大匹配。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
const int N = 3000;
const int M = 60;
const int inf = 0x7fffffff;
char map[M][M];
#define pb push_back
struct Edge{
int from,to,cap,flow;
Edge(){}
Edge(int from,int to,int cap,int flow):from(from),to(to),cap(cap),flow(flow){}
};
vector<Edge> G;
vector<int> V[N];
void add(int from, int to, int cap){
G.pb(Edge(from,to,cap,0));
G.pb(Edge(to,from,0,0));
int x=G.size();
V[from].pb(x-2);
V[to].pb(x-1);
}
int T, n, m, a, b, tar;
int id[M][M][2];
int sch(int x, int y, int d){
if(map[x][y]=='#' || x<0 || y<0) return ++b;
if(d) id[x][y][d] = sch(x-1, y, d);
else id[x][y][d] = sch(x, y-1, d);
return id[x][y][d];
}
int cur[N], d[N];
bool bfs(){
memset(d, -1, sizeof(d));
queue<int> Q;
Q.push(0);
d[0] = 0;
while(!Q.empty()){
int x=Q.front(); Q.pop();
for(int i=0; i<V[x].size(); i++){
Edge &e = G[V[x][i]];
if(d[e.to]==-1 && e.cap>e.flow){
d[e.to] = d[x]+1;
Q.push(e.to);
}
}
}
return d[tar]!=-1;
}
int dfs(int x, int v){
if(x==tar || v==0) return v;
int flow=0, f;
for(int &i=cur[x]; i<V[x].size(); i++){
int j = V[x][i];
Edge &e = G[j];
if(d[e.to]==d[x]+1 && (f=dfs(e.to, min(v,e.cap-e.flow)))>0){
flow += f;
v -= f;
e.flow += f;
G[j^1].flow -= f;
if(!v) break;
}
}
return flow;
}
int solve(){
G.clear();
for(int i=0; i<=tar; i++) V[i].clear();
for(int i=0; i<n; i++){
for(int j=0; j<m; j++){
if(map[i][j]=='*' && id[i][j][0]!=-1 && id[i][j][1]!=-1){
add(id[i][j][0], id[i][j][1], 1);
}
}
}
for(int i=1; i<=a; i++) add(0, i, 1);
for(int i=a+1; i<=b; i++) add(i, tar, 1);
int flow=0;
while(bfs()){
memset(cur, 0, sizeof(cur));
flow += dfs(0, inf);
}
return flow;
}
int main(){
scanf("%d", &T);
while(T--){
scanf("%d %d", &n, &m);
b = 0;
memset(id, -1, sizeof(id));
for(int i=0; i<n; i++){
scanf("%s", map[i]);
for(int j=m-1; j>=0; j--){
if(map[i][j]!='#' && id[i][j][0]==-1) id[i][j][0] = sch(i, j, 0);
}
}
a = b;
for(int i=n-1; i>=0; i--){
for(int j=0; j<m; j++){
if(map[i][j]!='#' && id[i][j][1]==-1) id[i][j][1] = sch(i, j, 1);
}
}
tar = b+1;
printf("%d\n", solve());
}
return 0;
}