*表示可以放
o表示不可以放
#表示障碍物
经典二分:
对于横着能相互到达的编号相同,
对于竖着能相互到达的编号相同,
建边表示该位置可以放的啊
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <string>
#include <iostream>
#include <algorithm>
#include <sstream>
#include <cmath>
using namespace std;
#include <queue>
#include <stack>
#include <vector>
#include <deque>
#define cler(arr, val) memset(arr, val, sizeof(arr))
typedef long long LL;
const int MAXN = 100200;
const int MAXM = 6000010;
const int INF = 0x3f3f3f3f;
const int mod = 1000000007;
char mp[90][90];
int num1[69][69],num2[68][69],g[2566][2566];
int gn,gm;
int link[2566];
bool used[2566];
bool dfs(int u)
{
for(int v=1; v<gm; v++)
if(g[u][v]&&!used[v])
{
used[v]=true;
if(link[v]==-1||dfs(link[v]))
{
link[v]=u;
return true;
}
}
return false;
}
int getmax()
{
int sum=0;
cler(link,-1);
for(int i=1; i<gn; i++)
{
cler(used,false);
if(dfs(i)) sum++;
}
return sum;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
// freopen("out.txt", "w", stdout);
#endif
int t,n,m;
cin>>t;
while(t--)
{
cler(mp,0);
cler(num1,0);
cler(num2,0);
cler(g,0);
cin>>n>>m;
for(int i=0; i<n; i++)
scanf("%s",mp[i]);
gn=gm=1;
for(int i=0; i<n; i++)
{
for(int j=0; j<m; j++)
{
if(mp[i][j]=='*')
num1[i][j]=gn;
else if(mp[i][j]=='#')
gn++;
}
gn++;
}
for(int i=0; i<m; i++)
{
for(int j=0; j<n; j++)
{
if(mp[j][i]=='*')
num2[j][i]=gm;
else if(mp[j][i]=='#')
gm++;
}
gm++;
}
for(int i=0; i<n; i++)
for(int j=0; j<m; j++)
g[num1[i][j]][num2[i][j]]=1;
cout<<getmax()<<endl;
}
return 0;
}
对于横着能相互到达的编号相同,
对于横着能相互到达的编号相同,