题意:大体上就是叫你在一张图中,确定几个位置,是存放机枪的数目达到最多。
分析:该题与经典的八皇后问题相似,只是该问题比八皇后问题多了有墙的限制,存放的位置多了一些选择。该题可以用搜索做但也可以用二分图做。因为该题的数据较少,所以搜索和二分图并无太大的区别。
先说一下搜索:
#include <stdio.h>
char map[5][5];
int ans,n;
bool Judg(int x,int y)//判断方法类似于八皇后问题
{
bool ok = false; //判断在同一水平直线上是否形成了对峙的机枪
map[x][y] = 'F';
for(int j = 0;j < n;j++)
{
if(map[x][j] == 'F')
{
if(ok)return false;
else ok = true;
}
if(map[x][j] == 'X')ok = false;
}
ok = false;
for(int i = 0;i < n;i++)
{
if(map[i][y] == 'F')
{
if(ok)return false;
else ok = true;
}
if(map[i][y] == 'X')ok = false;
}
return true;
}
void DFS(int x,int y,int cnt)
{
if(cnt>ans)ans = cnt;
if(y == n){x++;y = 0;}
if(x == n)return ;
if(map[x][y] == 'X'){
DFS(x,y+1,cnt);
}else
{
if(Judg(x,y))
DFS(x,y+1,cnt+1);
map[x][y] = '.';
DFS(x,y+1,cnt);
}
}
int main()
{
while(scanf("%d",&n),n)
{
for(int i = 0;i < n;i++)
scanf("%s",map[i]);
ans = 0;
DFS(0,0,0);
printf("%d\n",ans);
}
return 0;
}
二分图:
二分图最要是建图有一定的难度,话说我还没有完全的理解该题的建图真正含义。但正如楼教主说的,“虽然,我不懂这道题,但AC还是没问题的”。一下是借用他人博客的话。
建图方法:横竖分区。先看每一列,同一列相连的空地同时看成一个点,显然这样的区域不能够同时放两个点。这些点作为二分图的X部。同理在对所有的行用相同的方法缩点,作为Y部。
连边的条件是两个区域有相交部分。最后求最大匹配就是答案。
#include<stdio.h>
#include<string.h>
int n,RowN,ColN;
bool used[20];
char map[5][5];
int g[20][20],link[20],Row[5][5],Col[5][5];
int Find(int u)
{
for(int v = 1;v <= ColN;v++)
if(g[u][v]&&!used[v])
{
used[v]=true;
if(link[v]==-1||Find(link[v]))
{
link[v]=u;
return 1;
}
}
return 0;
}
int Hungary()
{
int ans = 0;
memset(link,-1,sizeof(link));
for(int u=1;u<=RowN;u++)
{
memset(used,0,sizeof(used));
ans += Find(u);
}
return ans;
}
int main()
{
while(scanf("%d",&n),n)
{
memset(Row,0,sizeof(Row));
memset(Col,0,sizeof(Col));
memset(g,0,sizeof(g));
for(int i = 0;i < n;i++)
{
scanf("%s",map[i]);
for(int j = 0;j < n;j++)if(map[i][j]=='X')
Row[i][j] = Col[i][j] = -1;
}
int i,j,cnt=0;
RowN = ColN = 0;
for(i=0;i<n;i++)
for(j=0;j<n;j++)
{
while(Row[i][j]==-1&&j<n)j++;
cnt ++;
while(Row[i][j]!=-1&&j<n)
{
Row[i][j]=cnt;
j++;
}
if(RowN<cnt)RowN=cnt;
} //printf("Row=%d\n",RowN);
for(cnt=j=0;j<n;j++)
for(i=0;i<n;i++)
{
while(Col[i][j]==-1&&i<n)i++;
cnt ++;
while(Col[i][j]!=-1&&i<n)
{
Col[i][j]=cnt;
i++;
}
if(ColN<cnt)ColN=cnt;
} //printf("vN=%d\n",ColN);
for(i=0;i<n;i++)
for(j=0;j<n;j++)if(Row[i][j]!=-1&&Col[i][j]!=-1)
g[Row[i][j]][Col[i][j]]=1;
printf("%d\n",Hungary());
}
return 0;
}