题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1045
题目大意:对于一个迷宫,其中’X’ 表示wall,‘.’表示空地,可以放置blockhouse,同一条直线上只能有一个blockhouse,除非有wall隔开,问在给出的图中最多能放置多少个blockhouse。
分析题意:
1、 此题有两种解法。第一种:暴力解法。从左往右,从上到下,对每一种情况进行深度优先的遍历,遍历过程中保存最大的blockhouse数。
2、 第二种方法:我们可以把原始图分别按行按列进行压缩。先将每一行,把每一行相连的空地看成一个点,因为这些区域无法同时放两个点,把这些点看成二分图的X部;同理,将每一列相连的空地看成一个点,再把这些点看成二分图的Y部。X部和Y部的点相连的条件是两个区域有相交的部分(即’.’的地方)。最后用匈牙利算法求最大二分匹配即可。
第一种方法,暴力法:
#include<stdio.h>
char maze[5][5];
int maxNum;
int n;
int isPlaceable(int x, int y){ //由于遍历顺序为从左往右,从上往下,所以只考虑上面和左边的点就行了
int i;
int flag;
flag = 1;
for(i=x-1; i>=0; i--){
if(maze[y][i] == '*'){
flag = 0;
return flag;
}
if(maze[y][i] == 'X'){
break;
}
}
for(i=y-1; i>=0; i--){
if(maze[i][x] == 'X'){
break;
}
if(maze[i][x] == '*'){
flag = 0;
return flag;
}
}
return flag;
}
void dfs(int x, int y, int num)
{
if(x==n-1 && y==n-1){
if(maze[y][x]=='.' && isPlaceable(x, y)){
num++;
}
if( num > maxNum){
maxNum = num;
}
return;
}
if(maze[y][x]=='.' && isPlaceable(x, y)){
maze[y][x] = '*';
if(x<n-1){
dfs(x+1, y, num+1);
}
else{
dfs(0, y+1, num+1);
}
maze[y][x] = '.';
}
if(x<n-1){
dfs(x+1, y, num);
}
else{
dfs(0, y+1, num);
}
return ;
}
int main()
{
int i;
while(scanf("%d", &n) != EOF){
if(n == 0){
break;
}
for(i=0; i<n; i++){
scanf("%s", maze[i]);
}
maxNum = 0;
dfs(0, 0, 0);
printf("%d\n", maxNum);
}
return 0;
}
第二种方法:最大二分匹配
#include<stdio.h>
#include<string.h>
#define N 20
int n;
int biMap[N][N];
int visited[N];
int matchLeft[N];
int matchRight[N];
char maze[5][5];
int counter1;
int counter2;
int res;
void constructBiMap()
{
int i, j;
int counter;
int inX[6][6];
int inY[6][6];
memset(biMap, 0, sizeof(biMap));
counter1 = 0;
for(i=0; i<n; i++){
for(j=0; j<n; j++){
if(maze[i][j] == '.'){
if(j==0 || maze[i][j-1]=='X'){
counter1++;
}
inX[i][j] = counter1;
}
}
}
counter2 = 0;
for(j=0; j<n; j++){
for(i=0; i<n; i++){
if(maze[i][j] == '.'){
if(i==0 || maze[i-1][j]=='X'){
counter2++;
}
inY[i][j] = counter2;
}
}
}
for(i=0; i<n; i++){
for(j=0; j<n; j++){
if(maze[i][j] == '.'){
biMap[inX[i][j]][inY[i][j]] = 1;
}
}
}
}
int DFSFindAugment(int u)
{
int i;
for(i=1; i<=counter2; i++){
if(biMap[u][i] && !visited[i]){
visited[i] = 1;
if(matchRight[i]==-1 || DFSFindAugment(matchRight[i])){
matchRight[i] = u;
matchLeft[u] = i;
return 1;
}
}
}
return 0;
}
void binaryMatch()
{
int i, j;
constructBiMap();
memset(matchLeft, -1, sizeof(matchLeft));
memset(matchRight, -1, sizeof(matchRight));
res = 0;
for(i=1; i<=counter1; i++){
if(matchLeft[i] == -1){
memset(visited, 0, sizeof(visited));
res += DFSFindAugment(i);
}
}
}
int main()
{
int i;
while(scanf("%d", &n)!=EOF && n!=0){
for(i=0; i<n; i++){
scanf("%s", maze[i]);
}
binaryMatch();
printf("%d\n", res);
}
return 0;
}