两天来学习搜索算法的小结

 

算法中需要使用搜索进行解决的内容很多,大致分为以下几类常用的搜索方式。

1、枚举。枚举运算量很大,需要预先确定枚举的定义域。

2、广度优先搜索(BFS )——通常可以用于计算图的连通性、单源最短路径、计算最小操作次数等。
3、深度优先搜索(DFS)——。经典题:火力中心布局。

 

BFS的占用的是队列的空间,DFS 占用的是栈的空间(因为递归)。BFS和DFS的空间复杂度恰好相反。对链状图,BFS最好(队列中最多只有1个元素),DFS最差(所有节点都在根节点的递归内)。对起点与其他所有点相邻的图,DFS最好(递归深度为1),BFS最差(队列中放满了所有与起点相邻的图)。

 

相对来说,BFS是比较简单的(恩,可能我做的水题)。

反正大致的模板就是

 

queue<type> q;

q.push(初始状态);

 

 while (!q.empty())

{

  type t = q.front() ;

  q.pop();

  遍历 t 的各个Next状态  next

  {

    if (next is legal)

      q.push(next); 计数或维护等;

  }

}

 

 但是BFS的状态数一多,需要的空间就会较大。因此就需要状态压缩,BUPT OJ上的1180就是一个典型的例子,但是状态压缩以及解压的时候,又会涉及效率,反正1180将80M的状态压缩到40K以后就超时了……

 

今天参考别人的代码,写了第一个DFS,POJ 1321。 相当的水。但是大牛的代码比我的简洁太多了。

DFS大致的模板就是

DFS(顶点)

{

  处理当前顶点,记录为已访问

  遍历与当前顶点相邻的所有未访问顶点

  {

      标记更改;

      DFS( 下一子状态);

      恢复更改;

  }

}

 

回溯法:DFS适用于 显式图,但是对于一些隐式关系,我们需要使用回溯法,通过定义或找到各个状态、边界条件、搜索范围、约束条件和最优解结果进行建模求解。

边界条件:达到某状态时,需要检查并确定是继续搜索还是回到上一状态的条件(例如当前已使用时间比当前最优解要长,此时就不需要再进行搜索)

搜索范围:当前从当前状态开始进行搜索的所有下一级状态。

搜索范围:

另外一定要注意,假如参与递归的参数不是通过传参形式的方式进入递归的话,那么一定要做好数据恢复。

Trace(当前状态)

{

    if 当前状态是结束状态

    {

         if 是最佳解: 记录。

         退出

    }

    遍历当前状态的各个邻接状态

    {

        if 当前状态满足约束条件 且 满足最优性要求 : Trace(子状态)

    }

}

 

回溯法经典题:任何大于1的自然数n,都可以拆分成若干个小于n的自然数之和,输入n,输出不同n的拆分方案。

 状态:对于一个拆分a1<=a2<=...a(k-1)<=ak, 下一拆分可以是 a1<=a2<=...a(k-1)<=m<=ak-m (其中a(k-1)<=m<=ak-m)


 

#include <stdio.h>
#include 
<string.h>
#include 
<stdlib.h>

int a[20];
int result = 0;
int num;

void Sum(int kx) //传入参数为拆分结果的最后一项的位置
{
    result 
= result + 1;
    printf(
"%d\t%d = ",result,num);
    
for ( int i = 1 ; i <= kx-1 ; i++)
        printf(
"%d +",a[i]);
    printf(
"%d\n",a[kx]);
    
int k = kx;
    
int l = a[k];
    
for (int m = a[k-1]; m <= l/2; m++)
    {
        a[k] 
= m;
        a[k
+1 ] = l-m;
        Sum(k
+1);
    }
}
int main()
{
    
while(1)
    {
        result 
= 0;
        scanf(
"%d"&num);
        
for (int i = 1 ; i < num; i++)
        {
            memset(a,
0,sizeof(a));
            a[
1= i;
            a[
2= num-i;
            Sum(
2);
        }
    }
    
return 0;
}

 

 

还有一个经典的题目是24点。

 

 

View Code
 1 //24 dian
 2 
 3 #include <iostream>
 4 #include <stdio.h>
 5 using namespace std;
 6 
 7 double a[4];
 8 bool b[4];
 9 double ans;
10 
11 bool judge(int step)
12 {
13     if (step == 3)
14     {
15        if ( a[3- ans < 1e-8 && a[3- ans > -(1e-8))
16           return true;
17        else
18            return false;
19     }
20     
21     //else
22     for ( int j = 0 ; j < 3; j++)
23         for (int i = j+1; i < 4; i++)
24         {
25             double temp;
26             if ( !b[i] && !b[j])
27             {
28                  temp = a[i];
29                  b[j] = true;
30                  
31                  a[i] = a[i] + a[j];
32                  if (judge(step + 1)) return true;
33                  a[i] = temp;
34                  
35                  a[i] = a[i] - a[j];
36                  if (judge(step + 1)) return true;
37                  a[i] = temp;
38                  
39                  a[i] = a[j] - a[i];
40                  if (judge(step + 1)) return true;
41                  a[i] = temp;
42                  
43                  a[i] = a[i] * a[j];
44                  if (judge(step + 1)) return true;
45                  a[i] = temp;
46                  
47                  if ( a[j] != 0)
48                  {
49                      a[i] = a[i] / a[j];
50                      if (judge(step + 1)) return true;
51                      a[i] = temp;
52                  }
53                  
54                  if (a[i] != 0)
55                  {
56                           a[i] = a[j] / a[i];
57                           if (judge(step + 1)) return true;
58                           a[i] = temp;
59                  }
60                  a[i] = temp;
61                  b[j] = false;          //回溯的时候要注意恢复现场
62             }
63         }
64     
65     return false;
66 }
67 
68 int main()
69 {
70     while (scanf("%lf%lf%lf%lf%lf"&a[0],&a[1],&a[2],&a[3],&ans) != EOF)
71     {
72           for ( int i = 0 ; i < 4; i++)
73               b[i] = false;
74           
75           if (judge(0))
76              cout << "Possible" << endl;
77           else
78               cout << "Impossible" << endl;
79     }
80 }

 


 拓扑排序应该也能归到这里吧,通常都是使用优先队列这个imba的数据结构。

View Code
//poj 1485 
#include <stdio.h>
#include 
<vector>
#include 
<queue>
#include 
<string.h>

using namespace std;
const int N = 100010;

//priority queue compare
struct less_comp
{
       
bool operator()(const int &a, const int &b)
       {
            
return a > b;
       }
};

vector
<int> vec[N];
int n,k,indegree[N];
priority_queue
< int, vector<int>, less_comp > q;

int main()
{
    
int n,k;
    
while(scanf("%d%d",&n,&k) && !(n==0 && k==0))
    {
        memset(indegree,
0,sizeof(indegree));
        

        
int first,last;
        
for (int i = 0 ; i < k ; i++)
        {
            scanf(
"%d%d",&first,&last);
            vec[first].push_back(last);
            indegree[last]
++;
        }
        
        
// get 0 degree
        for (int i = 1 ; i <= n ; i++)
        {
            
if ( indegree[i] == 0)
               q.push(i);
        }
        
        vector
<int>::iterator it;
        vector
<int>::iterator itend;
        
int cur;
        printf(
"ORDER:");
        
while(!q.empty())
        {
            cur 
= q.top();
            q.pop();
            itend 
= vec[cur].end();
            
for (it = vec[cur].begin(); it != itend; it++)
            {
                
if (--indegree[*it] == 0)
                {
                    q.push(
*it);
                }
            }
            vec[cur].clear();
            printf(
" %d",cur);
        }
        printf(
"\n");
    }
}

 

不过目前还没有遇到剪枝之类的题目。还是需要多做水题消化消化。
 

posted @ 2010-11-09 14:29  Hector  阅读(1082)  评论(0编辑  收藏  举报