算法中需要使用搜索进行解决的内容很多,大致分为以下几类常用的搜索方式。
1、枚举。枚举运算量很大,需要预先确定枚举的定义域。
2、广度优先搜索(BFS )——通常可以用于计算图的连通性、单源最短路径、计算最小操作次数等。
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 < 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点。
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的数据结构。
#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 " );
}
}