题意:N*M的矩阵,'.'代表空地,'0-9'代表古代建筑,我们如果选择了一个编号的古代建筑想要建立,那么对应就要
将该编号全部建筑建立起来,如果在空地上建筑,只建立当前点。问最多能够建立多少种建筑,并且每两种建筑之间
没有公共边。
思路:如果没有古代建筑,匈牙利就行,相邻的点建边,最后答案就是最大独立集=点数-匹配数(因为是双向边 所以/2).
这题有古代建筑,但是建筑数最多才10,所以我们可以枚举每个古代建筑是建立还是不建立,2^10复杂度。每次都把
这些建的周围的点和建筑点去除,建边跑下匈牙利就行了。
代码不太好写。。
代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn = 15;
const int maxm = 105;
char pic[maxn][maxn];
int n, m, ans, num, a[maxn];
bool book[maxn];
int is[maxn][maxn];
bool vis[maxm];
int match[maxm];
vector<int> g[maxm];
struct node
{
int x, y;
node(){}
node(int xx, int yy):x(xx), y(yy) {}
};
vector<node> pos[maxn];
bool dfs(int x)
{
for(int i = 0; i < g[x].size(); i++)
{
int to = g[x][i];
if(!vis[to])
{
vis[to] = 1;
if(!match[to] || dfs(match[to]))
{
match[to] = x;
return 1;
}
}
}
return 0;
}
int Hungary()
{
int res = 0;
memset(match, 0, sizeof(match));
for(int i = 0; i < n*m; i++)
{
memset(vis, 0, sizeof(vis));
res += dfs(i);
}
return res;
}
bool judge()
{
for(int i = 0; i < n; i++)
for(int j = 0; j < m; j++)
{
if(is[i][j] == 1)
{
int next[4][2] = {0, 1, 0, -1, 1, 0, -1, 0};
for(int k = 0; k < 4; k++)
{
int tx = i+next[k][0];
int ty = j+next[k][1];
if(tx >= 0 && tx < n && ty >= 0 && ty < m)
{
if(is[tx][ty] == 2) continue;
if(!is[tx][ty]) is[tx][ty] = 2;
else if(pic[tx][ty] == pic[i][j]) continue;
else return 0;
}
}
}
}
return 1;
}
void solve()
{
int cur = 0;
memset(is, 0, sizeof(is));
for(int i = 0; i < maxn; i++)
if(book[i])
{
cur++;
for(int j = 0; j < pos[i].size(); j++)
{
int x = pos[i][j].x;
int y = pos[i][j].y;
is[x][y] = 1;
}
}
if(!judge()) return ;
int all = 0;
for(int i = 0; i < maxm; i++)
g[i].clear();
for(int i = 0; i < n; i++)
for(int j = 0; j < m; j++)
{
if(!is[i][j] && pic[i][j] == '.') all++;
if(is[i][j] || pic[i][j] != '.') continue;
int next[4][2] = {0, 1, 0, -1, 1, 0, -1, 0};
for(int k = 0; k < 4; k++)
{
int tx = i+next[k][0];
int ty = j+next[k][1];
if(tx >= 0 && tx < n && ty >= 0 && ty < m && !is[tx][ty] && pic[tx][ty] == '.')
{
g[i*m+j].push_back(tx*m+ty);
}
}
}
int tmp = Hungary();
ans = max(ans, cur+(all-tmp/2));
}
void dfs2(int cur)
{
if(cur >= num)
{
solve();
return ;
}
book[a[cur]] = 1;
dfs2(cur+1);
book[a[cur]] = 0;
dfs2(cur+1);
}
int main(void)
{
int _, ca = 1;
cin >> _;
while(_--)
{
ans = 0;
for(int i = 0; i < maxn; i++)
pos[i].clear();
scanf("%d%d", &n, &m);
for(int i = 0; i < n; i++)
scanf(" %s", pic[i]);
num = 0;
for(int i = 0; i < n; i++)
for(int j = 0; j < m; j++)
{
if(pic[i][j] != '.')
{
if(pos[pic[i][j]-'0'].size() == 0)
a[num++] = pic[i][j]-'0';
pos[pic[i][j]-'0'].push_back(node(i, j));
}
}
memset(book, 0, sizeof(book));
dfs2(0);
printf("Case #%d: %d\n", ca++, ans);
}
return 0;
}