本题可以使用DFS直接爆搜出答案,不过这样类型的题目其实是个二分图的题解。
这个二分图,难不在Hungary算法,而是难在于建图。需要挺高的抽象思维的。
建图:
1 把同一行不被X分开的格子标同一个号码,被X分开的标下一个号码,这样做是为了缩点,不需要把所有的格子都分开标号,而且可以更方便建个更加小的图。
2 同理把同一列的格子标号
3 然后判断相同一个格子的行标号和列标号是有路径的,其他不在同一个格子的都是没有路径的。
4 这样就等于以行标号和列标号作为左右顶点,构建成一个二分图了
然后使用Hungary算法求二分图的最大匹配了。
真是非常巧妙的建模!
自己直接研究不出来,也是参考了别人的代码然后直接敲出来了。
做人要厚道,还是给个链接吧:http://www.cnblogs.com/kuangbin/archive/2011/08/09/2132830.html 不过他的是纯代码了,没说什么建模的。
#include <stdio.h>
#include <vector>
#include <string.h>
#include <algorithm>
#include <iostream>
#include <string>
#include <limits.h>
#include <stack>
#include <queue>
#include <set>
#include <map>
using namespace std;
int uN, vN;
int g[20][20];
int linker[20];
bool used[20];
char gra[5][5];
int graR[5][5];
int graL[5][5];
bool dfs(int u)
{
for (int v = 1; v <= vN; v++)
{
if (g[u][v] && !used[v])
{
used[v] = true;
if (-1 == linker[v] || dfs(linker[v]))
{
linker[v] = u;
return true;
}
}
}
return false;
}
int hungary()
{
int res = 0;
for (int i = 0; i < 20; i++)
{
linker[i] = -1;
}
for (int u = 1; u <= uN; u++)
{
memset(used, 0, sizeof(used));
if (dfs(u)) res++;
}
return res;
}
int main()
{
int n;
while (scanf("%d", &n) && n)
{
memset(graL, 0, sizeof(graL));
memset(graR, 0, sizeof(graR));
memset(g, 0, sizeof(g));
getchar();
for (int i = 0; i < n; i++)
{
gets(gra[i]);
}
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)
{
if (gra[i-1][j-1] == 'X')
graL[i][j] = graR[i][j] = -1;
}
}
vN = uN = 0;
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)
{
while (graR[i][j] == -1 && j <= n) j++;
if (j > n) break;
uN++;
while (graR[i][j] != -1 && j <= n)
{
graR[i][j] = uN;
j++;
}
}
}
for (int j = 1; j <= n; j++)
{
for (int i = 1; i <= n; i++)
{
while (graL[i][j] == -1 && i <= n) i++;
if (i > n) break;
vN++;
while (graL[i][j] != -1 && i <= n)
{
graL[i][j] = vN;
i++;
}
}
}
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)
{
if (graR[i][j] != -1) g[graR[i][j]][graL[i][j]] = 1;
}
}
printf("%d\n", hungary());
}
return 0;
}
本题一开始我是用DFS爆搜过了,因为数据一看这么少,肯定可以过的。不过本题爆搜好像也不太容易一次AC,本人一开始就没思考好,用错了思路,WA了几次,不画图模拟,出错的几率还是相当高的。
const int MAX_N = 8;
char Maze[MAX_N][MAX_N];
int N;
bool isLegal(int r, int c)
{
if (Maze[r][c] != '.') return false;
bool legal = true;
for (int i = r-1; i >= 0 && legal; i--)
{
if (Maze[i][c] == 'X') break;
else if (Maze[i][c] != '.') legal = false;
}
for (int i = r+1; i < N && legal; i++)
{
if (Maze[i][c] == 'X') break;
else if (Maze[i][c] != '.') legal = false;
}
for (int j = c-1; j >= 0 && legal; j--)
{
if (Maze[r][j] == 'X') break;
else if (Maze[r][j] != '.') legal = false;
}
for (int j = c+1; j < N && legal; j++)
{
if (Maze[r][j] == 'X') break;
else if (Maze[r][j] != '.') legal = false;
}
return legal;
}
int ans;
void dfs(int one = 0)
{
bool flag = false;
for (int i = 0; i < N; i++)
{
for (int j = 0; j < N; j++)
{
if (isLegal(i, j))
{
flag = true;
Maze[i][j] = '@';
dfs(one+1);
Maze[i][j] = '.';
}
}
}
if (flag)
{
ans = max(ans, one+1);//, cout<<one<<endl;;
}
}
int main()
{
while (~scanf("%d", &N) && N)
{
while (getchar() != '\n') ;
for (int i = 0; i < N; i++)
{
gets(Maze[i]);
}
ans = 0;
dfs();
printf("%d\n", ans);
}
return 0;
}