转化为最小可相交路径覆盖问题
#include <cstdio>
#include <vector>
#include <bitset>
#include <functional>
using namespace std;
int n, m, ans, a[21][21], mp[21][21][21][21];
char c;
bitset<404> vis;
int main()
{
scanf("%d%d", &n, &m);
vector<vector<int>> g(n * m + 1);
vector<int> f(n * m + 1, 0);
for (int i = 1; i <= n; ++i)
{
for (int j = 1; j <= m; ++j)
{
scanf(" %c", &c);
ans += (c - '0');
a[i][j] = c - '0';
if(a[i][j]){
if(a[i-1][j])mp[i-1][j][i][j]=1;
if(a[i][j-1])mp[i][j-1][i][j]=1;
}
}
}
for(int kk=1;kk<=n;++kk){
for(int k=1;k<=m;++k){
for(int ii=1;ii<=n;++ii){
for(int i=1;i<=m;++i){
for(int jj=1;jj<=n;++jj){
for(int j=1;j<=m;++j){
if(ii!=jj&&i!=j){
if(mp[ii][i][kk][k]&&mp[kk][k][jj][j]){
mp[ii][i][jj][j]=1;
}
}
}
}
}
}
}
}
for(int i=1;i<=n;++i){
for(int ii=1;ii<=m;++ii){
for(int j=1;j<=n;++j){
for(int jj=1;jj<=m;++jj){
if(mp[i][ii][j][jj]){
g[(i-1)*m+ii].push_back((j-1)*m+jj);
}
}
}
}
}
function<bool(int)> ck = [&](int x) -> bool
{
for (vector<int>::iterator it = g[x].begin(); it != g[x].end(); ++it)
{
if (!vis[*it])
{
vis[*it] = 1;
if (!f[*it] || ck( f[*it]))
{
f[*it] = x;
return true;
}
}
}
return false;
};
for (int i = 1; i <= n*m; ++i)
{
vis.reset();
if (ck(i))
{
ans -= 1;
}
}
printf("%d", ans);
}