在地图中有一些障碍物,同一行或同一列不能放置炮台,否则会互相摧毁,除非有障碍物分隔开。
这题范围小,用DFS不难,不过用二分图匹配十分巧妙。而且数据范围大了DFS应该就不行了。
同一行或同一列不能同时有炮台,和二分图匹配中每个点最多配对一次相对应。
我们将可放置炮台位置的x和y建边,注意被障碍物分隔开的同一行要处理成不同的行,这样跑一边二分图最大匹配就是答案。
DFS代码:
char mp[10][10];
int sumx[40];
int sumy[40];
int n, ans;
int vis[40][40];
bool check(int x, int y, int sum)
{
int xx, yy;
xx = x - 1, yy = y;
while (xx >= 1 && mp[xx][yy] != 'X')
{
for (int i = 1; i <= sum; i++)
{
if (xx == sumx[i] && yy == sumy[i])
return false;
}
xx--;
}
xx = x + 1, yy = y;
while (xx <= n && mp[xx][yy] != 'X')
{
for (int i = 1; i <= sum; i++)
{
if (xx == sumx[i] && yy == sumy[i])
return false;
}
xx++;
}
xx = x, yy = y - 1;
while (yy >= 1 && mp[xx][yy] != 'X')
{
for (int i = 1; i <= sum; i++)
{
if (xx == sumx[i] && yy == sumy[i])
return false;
}
yy--;
}
xx = x, yy = y + 1;
while (yy <= n && mp[xx][yy] != 'X')
{
for (int i = 1; i <= sum; i++)
{
if (xx == sumx[i] && yy == sumy[i])
return false;
}
yy++;
}
return true;
}
void dfs(int x, int y, int sum)
{
ans = max(ans, sum);
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)
{
if (!vis[i][j] && mp[i][j] == '.' && check(i, j, sum))
{
sumx[sum + 1] = i;
sumy[sum + 1] = j;
vis[i][j] = 1;
dfs(i, j, sum + 1);
vis[i][j] = 0;
}
}
}
}
int main()
{
while (~scanf("%d", &n) && n)
{
ans = 0;
fill(vis[0], vis[0] + 40 * 40, 0);
for (int i = 1; i <= n; i++)
scanf("%s", mp[i] + 1);
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)
{
if (mp[i][j] == '.')
{
sumx[1] = i;
sumy[1] = j;
vis[i][j] = 1;
dfs(i, j, 1);
vis[i][j] = 0;
}
}
}
printf("%d\n", ans);
}
return 0;
}
二分图匹配代码:
char mp[10][10];
int pre[10][10][2];
int n;
void getpre()
{
int num = 0;
for (int i = 1; i <= n; i++)
{
int flag = 0;
for (int j = 1; j <= n; j++)
{
if (mp[i][j] == '.' && !flag)
{
flag = 1;
num++;
}
if (mp[i][j] == 'X')
flag = 0;
pre[i][j][0] = num;
}
}
num = 1;
for (int j = 1; j <= n; j++)
{
int flag = 0;
for (int i = 1; i <= n; i++)
{
if (mp[i][j] == '.' && !flag)
{
flag = 1;
num++;
}
if (mp[i][j] == 'X')
flag = 0;
pre[i][j][1] = num;
}
}
}
struct node
{
int v, next;
} edge[100];
int head[100], ct = 1;
void add(int u, int v)
{
edge[ct].v = v;
edge[ct].next = head[u];
head[u] = ct++;
}
bool vis[100];
int linker[100];
bool dfs(int u)
{
for (int i = head[u]; i; i = edge[i].next)
{
int v = edge[i].v;
if (!vis[v])
{
vis[v] = 1;
if (!linker[v] || dfs(linker[v]))
{
linker[v] = u;
return 1;
}
}
}
return 0;
}
void HUNGARY()
{
int res = 0;
fill(linker, linker + 100, 0);
for (int i = 1; i <= 50; i++)
{
fill(vis, vis + 100, false);
if (dfs(i))
res++;
}
printf("%d\n", res);
}
int main()
{
while (~scanf("%d", &n) && n)
{
ct = 1;
fill(head, head + 100, 0);
for (int i = 1; i <= n; i++)
scanf("%s", mp[i] + 1);
getpre(); //预处理出 行列关系 进行建图
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
if (mp[i][j] == '.')
add(pre[i][j][0], pre[i][j][1]);
HUNGARY();
}
return 0;
}