搜索

DFS, BFS, 剪枝, 迭代加深

void dfs()//参数用来表示状态  
{  
  if(到达终点状态)  
  {  
    pass//根据题意添加  
    return;  
  }  
  if(越界或者是不合法状态)  
    return;  
  if(特殊状态)//剪枝
    return ;
  for(扩展方式)  
  {  
    if(扩展方式所达到状态合法)  
    {  
      修改操作;//根据题意来添加  
      标记;  
      dfs();  
      (还原标记);  
      //是否还原标记根据题意, 如果加上就是回溯法  
    }  
  }  
}

剪枝

1、可行性剪枝
当前状态和题意不符,并且由于题目可以推出,往后的所有情况和题意都不符,那么就可以进行剪枝,直
接把这种情况及后续的所有情况判负,直接返回。

即:不可行,就返回。

2、排除等效冗余
当几个枝桠具有完全相同的效果的时候,只选择其中一个走就可以了。

即:都可以,选一个。

3、最优性剪枝
当搜到一半的时候,已经比已经搜到的最优解要不优了,那么这个方案肯定是不行的,即刻停止搜索,进行回溯。

即:有比较,选最优。

4、顺序剪枝
普遍来讲,搜索的顺序是不固定的,对一个问题来讲,算法可以进入搜索树的任意的一个子节点。但假如我们要搜索一个最小值,而非要从最大
值存在的那个节点开搜,就可能存在搜索到最后才出解。而我们从最小的节点开搜很可能马上就出解。这就是顺序剪枝的一个应用。一般来讲,
有单调性存在的搜索问题可以和贪心思想结合,进行顺序剪枝。

即:有顺序,按题意。

5、记忆化
记录搜索的每一个状态,当重复搜索到相同的状态的时候直接返回。

即:搜重了,直接跳。

queue<int> q;
void bfs()
{
  q.push();           //入队起始状态
  while(!q.empty())   //非空
  {                   
    x = q.pop();        //非空
    for()             //遍历所有可到达的状态
    {                 
      q.push();       //把后续状态入队
    }
  }
}
//迭代加深iterative deepen
//给dfs加上深度限制,并且不断放宽限制直到找到最优解
int limit = 0;                    //深度限制
bool dfs(int x)
{
  if(x > limit)   return false;   //深度限制
  if(check())     return true;
  ...
  return false;
}
int main()
{
  for(;;)
  {
    ++limit;                      //放宽深度限制
    if(dfs())    break;           //找到最优解
  }
  return 0;
}

一个DFS实例,全排列

int temp[10] = {0};
bool vis[10] = {false};
int n;

void dfs(int x){
  if(x == n+1)
  {
    for(int i=1; i<=n; i++)
    {
      cout << temp[i] << " ";
    }
    cout << endl;
  }
  return;

  for(int i=1; i<=n; i++)
  {
    if(!vis[i])
    {
      temp[x] = i;
      vis[i] = true;
      dfs(x + 1);
      vis[i] = false;
    }
  }
  return;
}