hdu 1045 Fire Net

题目

拿到这道题刚开始就觉得是bfs,其实自己一直不太能清晰的分析出一个题用的是bfs,还是dfs。尽管他们的原理我都大概知道,但可能就是 因为我只是大概知道吧。。总是觉得dfs和bfs这两个东西是可以相互使用的。

下面对dsf和bfs做一个总结吧:

DFS在于从一个初始状态出发,一直转移状态直到搜到目标或搜到状态无法进行转移为止,而BFS在于一层一层地扩展状态,这样首先找到的目标便一定是用时或步数最少的。

DFS几乎适用于所有情况,因为这本身是一种遍历所有状态的搜索,只不过在寻找最小步或最小时间的情况下比较慢,无法快速找到目标,但在程序世界里DFS本身也有不适用的情况,如果状态没有下限即转移的深度没有下限那么便无法深搜,同样,BFS可能存在一层状态都扩展不完的情况,这样便才会有迭代加深搜索等扩展搜索的出现,它结合了两者的优点且实际应用效果不错。紫书上面的名词“解答树”便很好地描述了所有状态转移的过程,当然这个似乎与我们无关,但是其实也是一种刻画搜索过程的有利工具。

在解答题目时你需要明白一下几点:

1、如何进行状态的转移,简单地说怎么进行下一步的选择

2、是否需要标记已经转移过的状态以及怎么标记已经转移过的状态以不重复转移,你不能单一地判断,也就是要综合所给的题中所有出现的变化,在这个阶段中,我标记这个阶段时的状态,因为很可能不止“你”在变化,图中的情况也在变化。

 3、怎么去除没必要的或不存在的状态,因为有些状态是不需要进行转移或扩展的。

题意:有一个n行n列的网格,可以往里面填炮台,炮台的炮可以沿着行或者列发射,但是不可以穿过墙。现在问最多可以放多少个炮台,使得它们不会打到对方。

注意:表示一个点的方式可以只用一个数,如这题中的k,比如说一个点的坐标是(x,y),k=x*n+y,n为每行的列数。要恢复成原来的坐标就是x=k/n,y=k%n就可以了。

#include <iostream>
#include <cstdio>
#include <queue>
#include <cstring>
using namespace std;

int n,Max;
char mp[5][5];

int check(int k)
{
    int r=k/n,c=k%n;
    for(int i=c;i>=0;i--)//判断这一行前面有没有炮台
    {
        if(mp[r][i]=='X') break;
        else if(mp[r][i]=='@') return 0;
    }
    for(int i=r;i>=0;i--)//判断这一列前面有没有炮台
    {
        if(mp[i][c]=='X') break;
        else if(mp[i][c]=='@') return 0;
    }
    return 1;
}
void dfs(int k,int cnt)
{
    if(k==n*n)//把棋盘遍历完一次后,更新Max
    {
        if(Max<cnt) Max = cnt;
        return;
    }
    if(mp[k/n][k%n]=='.'&&check(k))//可以放炮
    {
        mp[k/n][k%n]='@';
        dfs(k+1,cnt+1);
        mp[k/n][k%n]='.';
    }
    dfs(k+1,cnt);//不可以放炮,或者回溯到此如果选择不放炮
}
int main()
{
  while(~scanf("%d",&n),n)
  {
      for(int i=0;i<n;i++)
        scanf("%s",mp[i]);
      Max = -1;
      dfs(0,0);
      printf("%d\n",Max);
  }

    return 0;
}

还有就是递归回溯到那个地方总是感觉有点不是那么清楚,递归到某个点的时候你可以选择在这个点放炮和不在这个点放炮,回溯到时候就是包含不再这个点放炮的这么一个操作。

猜你喜欢

转载自blog.csdn.net/qie_wei/article/details/81162418