最基础的“穷竭搜索”

Posted ymir-taomee

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了最基础的“穷竭搜索”相关的知识,希望对你有一定的参考价值。


 栈(Stack)

 1 #include <stack>
 2 #include <cstdio>
 3  
 4 using namespace std;
 5 
 6 int main(int argc, char * argv[])
 7 {
 8     stack<int> s;
 9     s.push(1);
10     s.push(2);
11     s.push(3);
12     printf("%d
",s.size());
13     printf("%d
",s.empty()); 
14     printf("%d
",s.top());
15     s.pop();
16     printf("%d
",s.top());
17     s.pop();
18     printf("%d
",s.top());//stack非空 
19     s.pop();
20     printf("%d
",s.size());
21     printf("%d
",s.empty()); 
22     return 0; 
23 } 

 


 

队列(Queue)

 1 #include <queue>
 2 #include <cstdio>
 3 
 4 using namespace std;
 5 
 6 int main(int argc, char * argv[])
 7 {
 8     queue<int> que;
 9     que.push(1);
10     que.push(2);
11     que.push(3);
12     printf("%d
",que.size());
13     printf("%d
",que.front());
14     printf("%d
",que.back());
15     que.pop();
16     printf("%d
",que.size());
17     printf("%d
",que.front());
18     printf("%d
",que.back());
19     que.pop();
20     printf("%d
",que.size());
21     printf("%d
",que.front());
22     printf("%d
",que.back());
23     que.pop();
24     printf("%d
",que.size());
25     printf("%d
",que.front());//队列为空,返回值是不确定的
26     printf("%d
",que.back());//队列为空,返回值是不确定的 
27     printf("%d
",que.empty());
28 } 

 


 

部分和问题

  • 题目大意:给定整数a1,a2,…,an,判断是否可以从中选出若干数,使它们的和恰好为k
  • 限制条件:
    • 1≤n≤20
    • -108≤ai≤108
    • -108≤k≤108
  • 题解:深度优先搜索,从a1开始按顺序决定每个数加或不加,在全部n个数都决定后在判断它们的和是不是k即可。因为状态数是2n,所以复杂度是O(2n)。
  • 代码:
    技术分享图片
     1 #include <iostream>
     2 
     3 using namespace std;
     4 
     5 bool dfs(int, int);
     6 
     7 int n,k;
     8 int * a;
     9 
    10 int main()
    11 {
    12     cin >> n >> k;
    13     a = new int[n];
    14     for (int i=0; i<n; i++)
    15     {
    16         cin >> a[i];
    17     }
    18     bool f=dfs(0,0);
    19     if (f) cout << "Yes!
    ";
    20     else cout << "No!
    "; 
    21 }
    22 
    23 bool dfs(int i, int s)//已经从前n项得到了和s
    24 {
    25     if (i==n) return s==k;//如果前n项都已经计算过了,返回s与k是否相等 
    26     if (dfs(i+1,s)) return true;// 不加上a[i]的情况 
    27     if (dfs(i+1,s+a[i])) return true;//加上a[i]的情况 
    28     return false;//无论是否加上a[i]都不能凑成k就返回false 
    29 }
    部分和问题

 

Lake Counting(POJ 2386)

  • 原题如下:
    Lake Counting
    Time Limit: 1000MS Memory Limit: 65536K
    Total Submissions: 44746 Accepted: 22116

    Description

    Due to recent rains, water has pooled in various places in Farmer John‘s field, which is represented by a rectangle of N x M (1 <= N <= 100; 1 <= M <= 100) squares. Each square contains either water (‘W‘) or dry land (‘.‘). Farmer John would like to figure out how many ponds have formed in his field. A pond is a connected set of squares with water in them, where a square is considered adjacent to all eight of its neighbors. 

    Given a diagram of Farmer John‘s field, determine how many ponds he has.

    Input

    * Line 1: Two space-separated integers: N and M 

    * Lines 2..N+1: M characters per line representing one row of Farmer John‘s field. Each character is either ‘W‘ or ‘.‘. The characters do not have spaces between them.

    Output

    * Line 1: The number of ponds in Farmer John‘s field.

    Sample Input

    10 12
    W........WW.
    .WWW.....WWW
    ....WW...WW.
    .........WW.
    .........W..
    ..W......W..
    .W.W.....WW.
    W.W.W.....W.
    .W.W......W.
    ..W.......W.

    Sample Output

    3

    Hint

    OUTPUT DETAILS: 

    There are three ponds: one in the upper left, one in the lower left,and one along the right side.
  • 题解:从任意的‘W‘开始,不停地把邻接的部分用‘.‘代替,1次dfs后与初始的这个W连接的所有‘W‘就都被替换成了‘.‘,因此直到图中不再存在w为止,总共进行dfs的次数就是答案了,复杂度是O(8*n*m)=O(m*n)
  • 代码:
    技术分享图片
     1 #include <iostream>
     2 
     3 using namespace std;
     4 
     5 int n,m;
     6 char ** a;
     7 
     8 void dfs(int, int);
     9 
    10 int main()
    11 {
    12     cin >> n >> m;
    13     a = new char*[n];
    14     for (int i=0; i<n; i++) a[i]=new char[m];
    15     for (int i=0; i<n; i++)
    16     {
    17         for (int j=0; j<m; j++)
    18         {
    19             cin >> j[i[a]];
    20         }
    21     }
    22     int s=0;
    23     for (int i=0; i<n; i++)
    24     {
    25         for (int j=0; j<m; j++)
    26         {
    27             if (j[i[a]]==W) 
    28             {
    29                 dfs(i,j);
    30                 ++s;
    31             }
    32         }
    33     }
    34     cout << s << endl;
    35 }
    36 
    37 void dfs(int x, int y)
    38 {
    39     y[x[a]] =.;
    40     for (int dx=-1; dx<=1; dx++)
    41     {
    42         for (int dy=-1; dy<=1; dy++)
    43         {
    44             int xx=x+dx, yy=y+dy;
    45             if (xx>=0 && xx<n && yy>=0 && yy<m && yy[xx[a]]==W) dfs(xx,yy);
    46         }
    47     }
    48 }
    Lake Counting

 迷宫的最短路径

  • 题目大意:给定一个大小为N*M的迷宫,迷宫由通道和墙壁组成,每一步可以向邻接的上下左右四格的通道移动,要求出从起点到终点所需的最小步数。假定从起点一定可以移动到终点。
  • 限制条件:N,M≤100
  • 题解:宽度优先搜索按照距开始状态由近及远的顺序进行搜索(只要将已经访问的状态用标记管理起来),因此可以很容易地用来求最短路径、最少操作之类问题的答案。这个问题中状态仅仅是目前所在位置的坐标,因此可以构造成pair或者编码成int来表达状态。当状态更加复杂时,就需要封装成一个类来表示状态了。复杂度是O(4*n*m)=O(n*m)
  • 代码:
    技术分享图片
     1 #include <iostream>
     2 #include <queue>
     3 using namespace std;
     4 typedef pair<int,int> P;
     5 
     6 const int INF=100000000;
     7 const int MAX_N=100;
     8 const int MAX_M=100;
     9 char maze[MAX_N][MAX_M+1];
    10 int n,m;
    11 int sx=0,sy=1;
    12 int tx=9,ty=8;
    13 const int dx[4]{-1,0,0,1};
    14 const int dy[4]{0,1,-1,0};
    15 int d[MAX_N][MAX_M];
    16 
    17 int bfs();
    18 
    19 int main()
    20 {
    21     cin >> n >> m;
    22     for (int i=0; i<n; i++)
    23         for (int j=0; j<m; j++)
    24             cin >> j[i[maze]];
    25     cout << bfs();
    26 }
    27 
    28 int bfs()
    29 {
    30     queue<P> que;
    31     for (int i=0; i<n; i++)
    32         for (int j=0; j<n; j++)
    33             j[i[d]]=INF;
    34     que.push(P(sx,sy));
    35     sy[sx[d]]=0;
    36     while (que.size())
    37     {
    38         P p=que.front();
    39         que.pop();
    40         if (p.first==tx && p.second==ty) break;
    41         for (int i=0; i<4; i++)
    42         {
    43             int xx=p.first+dx[i];
    44             int yy=p.second+dy[i];
    45             if (xx>=0 && xx<n && yy>=0 && yy<m && yy[xx[maze]]!=# && yy[xx[d]]==INF)
    46             {
    47                 que.push(P(xx,yy));
    48                 yy[xx[d]]=p.second[p.first[d]]+1;
    49             }
    50         }
    51     }
    52     return ty[tx[d]];
    53 }
    迷宫的最短路径

 特殊状态的枚举

虽然生成可行解空间多数采用深度优先搜索,但在状态空间比较特殊时其实可以很简短地实现

如,C++标准库中提供了next_permutation函数,可以把n个元素共n!种不同的排列生成出来

又如,通过位运算,可以枚举n个元素中取出k个的共C(n,k)种状态或是某个集合中的全部子集等

贴一段书上的代码:

 1 bool used[MAX_N];
 2 int perm[MAX_N];
 3 
 4 void permutation1(int pos, int n)
 5 {
 6     if (pos==n)
 7     {
 8         /*
 9          *这里编写需要对perm进行的操作 
10          */
11         return ; 
12     }
13     for (int i=0; i<n; i++)
14         if (!used[i])
15         {
16             perm[pos]=i;
17             used[i]=true;
18             permutation1(pos+1,n);
19             used[i]=false;
20         }
21     return ;
22 }
23 _______________________________________________
24 #include <algorithm>
25 //即使有重复的元素也会生成所有的排列
26 //next_permutation是按照字典序来生成下一个排列的
27 int perm2[MAX_N];
28 void permutation2(int n)
29 {
30     for (int i; i<n; i++) perm2[i]=i;
31     do
32     {
33         /*
34          *这里编写需要对perm2进行的操作 
35          */
36     }
37     while (next_permutation(perm2, perm+n));
38     //所有的排列都生成后,next_permutation会返回false 
39     return ;
40 }

 







以上是关于最基础的“穷竭搜索”的主要内容,如果未能解决你的问题,请参考以下文章

1.初级篇——最基础的"穷竭搜索”

第 2 章:初出茅庐初级篇 - 2.1 穷竭搜索

算法基础系列第三章——层层推进的BFS

Exhaustive Search - 穷竭搜索

穷竭搜索: POJ 2718 Smallest Difference

poj2718Smallest Difference (穷竭搜索)