【原题链接】
http://[2001:da8:b000:6221:213:72ff:fe8f:5269]/joj/showproblem.php?pid=1017 (为ipv6地址)
【题目大意】
假设我们有一个有直线街道的方形城市。城市的地图是由N列和N行构成的方形平面,每条表示一条街道或一段墙。
一个碉堡有四个开口用于射击。这四个开口分别面向北、东、南和西。每个开口都有一个挺机枪。假设子弹的威力很大,可以穿越任何距离而且可以破坏掉线上的碉堡。另一方面墙是非常结实的,可以
挡住子弹。
目标是在城市中尽可能多的放置碉堡而互不摧毁。碉堡的布局规定是在地图的水平线或垂直列上没有两个碉堡,除非他们中间有墙隔开。在这个问题上我们会考虑有墙的方形小城市(最多4*4)
你的任务是写一个程序,给出地图的描述,计算出城市中合规定地放置的最大碉堡数目。输入包括一张或多张地图描述,跟着一行以0结束输入。每张地图描述开始以N作为一行,N是城市的大小。N最多是4。接下来的N行每行描述地图中的一行,以一个‘.’象征一个空地,以大写字母‘X’象征一堵墙。在输入过程中没空格。
每组测试输出一行一个数,即城市中按规定放置的最大碉堡数。
【解题思路】
深度优先搜索,枚举所有情况,找到最优解,详见代码。
【备注】
此题为深搜的简单题,若对递归和深搜原理理解不深acmer可研究下此题,注意递归的出口,防止递归进入死循环造成栈溢出。
【源程序】
[code]
#include <iostream>
using namespace std;
char map[5][5];
int size,ans;
bool canPut(int x, int y)
{//此函数检验该处是否可放
int i;
if(map[x][y]=='X') return 0;
if(map[x][y]=='#') return 0;
for(i=x;i>=0;i--)
{
if(map[i][y]=='X') break;
if(map[i][y]=='#') return 0;
}
for(i=x+1;i<size ;i++)
{
if(map[i][y]=='X') break;
if(map[i][y]=='#') return 0;
}
for(i=y;i>=0;i--)
{
if(map[x][i]=='X') break;
if(map[x][i]=='#') return 0;
}
for(i=y;i<size;i++)
{
if(map[x][i]=='X') break;
if(map[x][i]=='#') return 0;
}
return 1;
}
bool allPut()
{//此函数检验此图是否有处可放
int i,j;
for(i=0;i<size;i++)
{
for(j=0;j<size;j++) if(canPut(i,j)) break;
if(j<size) return 0;
}
return 1;
}
void dfs(int num)//num表示已放的碉堡数
{
int i,j;
if(allPut()) { ans=ans>num?ans:num; return; }
//如果已经无地可放,记录此时放入的碉堡数并更新结果,返回上一层
for(i=0;i<size;i++) for(j=0;j<size;j++)
{
if(!canPut(i,j)) continue;//如果此处不可放 看下处
map[i][j]='#';//此处放碉堡
dfs(num+1);//递归到下层检验是否可再放
map[i][j]='.';//下层不可再放,将此处碉堡清空,看另一个分支
}
}
int main()
{
int i,j;
while(cin>>size,size)//图大小,遇0结束
{
for(i=0;i<size;i++) for(j=0;j<size;j++) cin>>map[i][j];
//输入图
ans=0;
dfs(0);//深度优先搜索
cout<<ans<<endl;//输出结果
}
return 0;
}
[/code]