穷举搜索
对于一些困难的问题,我们只能穷举(brut force)搜索,是的,我们知道“穷举搜索”这个词,可是,具体怎么穷举呢?
很多问题可以归结到图的搜索,对于图的搜索,大家应该都知道 DFS 和 BFS,然而可能没有多少人知道如何对图做穷举搜索。我先举一个最简单的例子:哈米尔顿环(hamilton cycle),不知道的,可以去维基百科上去查。
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <vector>
#include <algorithm>
using namespace std;
int start = 0;
int N;
vector<vector<int> > G;
vector<int> P; // current path/stack
vector<int> D; // vertex depth in stack, -1 indicate not yet discovered
// so D also serve as Mark array of DFS
void printham() {
printf("found hamilton cycle: ");
for (int i = 0; i < N; ++i)
printf("%d ", P[i]);
printf("\n");
}
void hamilton(int x, int k) {
if (k == N) {
assert(0); // never goes here
} else {
D[x] = k; // mark x
P[k] = x; // put x into the path
for (int j = 0, c = G[x].size(); j < c; ++j) {
int y = G[x][j]; // Edge(x to y)
if (D[y] != -1) { // found a cycle
// (1 + k - D[y]) is the cycle length
// so the condition is also (D[y] == 0 && k == N-1)
if (y == start && k == N-1)
printham(); // this is a hamilton cycle
} else // not yet discovered
hamilton(y, k+1);
}
D[x] = -1; // un-mark
}
}
int main(int argc, char* argv[])
{
int lineno = 1;
while (!feof(stdin)) {
int x, y;
int fields = scanf("%d %d\n", &x, &y);
if (fields == 2) {
if (min(x, y) < 0) {
fprintf(stderr, "invalid vertex number at line %d\n", lineno);
return 3;
}
if (G.size() < (size_t)max(x, y) + 1)
G.resize(max(x, y) + 1);
G[x].push_back(y);
} else {
fprintf(stderr, "bad record at line %d\n", lineno);
return 3;
}
lineno++;
}
N = G.size();
P.resize(N);
D.resize(N, -1);
if (argc >= 2)
start = atoi(argv[1]);
else
start = 0;
hamilton(start, 0);
return 0;
}
为了突出递归的逻辑,这个程序把所有(每次递归都相同的)函数参数换成了全局变量,从软件工程角度讲这是有问题的,但是作为示例,逻辑上更清楚一些。这个程序从 stdin 读取一个图,这个图共 N 个结点,结点编号是 0~N-1。每行是一条边 src dest,中间用空白分隔。
从代码效率上讲,这个程序也也不够高效,一个在数据结构上(how to optimize vector<vector<int> > G ?)和程序逻辑(非递归) 上充分优化的版本,大约比这个要快10倍。
这个程序也接受一个参数 start ,表示搜索的起始结点,start 的默认值是 0。
下面是一个图的示例(g1.txt):
0 1
1 2
3 5
2 4
5 1
0 2
2 3
3 4
5 0
4 5
运行 hamilton 3 < g1.txt
输出结果是:found hamilton cycle: 3 4 5 0 1 2
穷举的一般代码框架是:
bruteforce(x, depth) {
if (depth == max_depth) {
// ....
} else {
mark[x] = true;
for (y : x.children) {
if (mark[x])
// ...
else
bruteforce(y, depth+1);
}
mark[x] = false; // this is the only diff with DFS
}
}
浙公网安备 33010602011771号