世上最可怕的事就是比你聪明的人,比你还努力还认真。
序言:启发式搜索是一种引用广泛的搜索技巧,它通过构造一个估价函数在搜索前或搜索中途就发现某种搜索不符合题意,因此可以直接回溯或进入下一层搜索。启发式搜索的思想比较抽象,我们用例题的方式介绍。
例1:采药
有N种物品和一个容量为W的背包,每种物品有重量wi和价值vi两种属性,要求选若干个物品(每种物品只能选一次)放入背包,使背包中物品的总价值最大,且背包中物品的总重量不超过背包的容量。
解析
不难看出,启发式搜索的重点就是如何写估价函数。在这道题当中,我们很容易看出的两个标准,即容量与价值。即
- 当超过了容量时,解不成立(容量)
- 舍弃某个物品后,如果剩余所有未取物品的价值和背包中物品价值的和小于当前的最大解,则解不成立(价值)
代码
估价函数,有了上面的解析,自己过一遍就能明白。每个变量的意义可以看下面的完整代码
int f(int i)
{
int sum_vol;
for (int i = 0; i < n; i++) {
if (book[i] == 1)sum_vol += s_val[i];
}
if (sum_vol > w)return 0;
int max_val=0;
for (int j = 0; j < i; j++) {
if (book[j] == 1)max_val += s_val[j];
}
for (int j = i; j < n; j++) {
max_val += s_val[j];
}
if (max_val <= ans)return 0;
}
完整代码
#include<iostream>
#include<algorithm>
using namespace std;
int* book;//在当前搜索情况中是否取了这个物品
int* s_val;//单个物品的价值
int* s_vol;//单个物品的体积
int n;//物品种数
int w;//背包体积
int ans = 0;//存储最大价值解的变量
int now_val;//存储在当前搜索情况中的总价值
int* ans_book;//存储取最大价值时的取法
void ini()
{
scanf("%d %d", &n, &w);
book = (int*)malloc(sizeof(int) * n);
memset(book, 0, sizeof(int) * n);
ans_book = (int*)malloc(sizeof(int) * n);
memset(ans_book, 0, sizeof(int) * n);
s_val = (int*)malloc(sizeof(int) * n);
s_vol = (int*)malloc(sizeof(int) * n);
for (int i = 0; i < n; i++) {
scanf("%d %d", &s_val[i], &s_vol[i]);
}
}
int f(int i)
{
int sum_vol;
for (int i = 0; i < n; i++) {
if (book[i] == 1)sum_vol += s_val[i];
}
if (sum_vol > w)return 0;
int max_val=0;
for (int j = 0; j < i; j++) {
if (book[j] == 1)max_val += s_val[j];
}
for (int j = i; j < n; j++) {
max_val += s_val[j];
}
if (max_val <= ans)return 0;
}
void dfs(int i)
{
if (i == n)return;
if (now_val > ans) {
ans = now_val;
for (int i = 0; i < n; i++)ans_book[i] = book[i];
}
else {
book[i] = 1;
now_val += s_val[i];
if (f(i))dfs(i + 1);
book[i] = 0;
now_val -= s_val[i];
}
}
int main(void)
{
ini();
dfs(0);
printf("%d\n", ans);
for (int i = 0; i, n; i++) {
printf("%d", ans_book[i]);
}
}
由此可见,当写出估价函数之后,剩下的就只是普通的dfs了。
还有另一种非常经典的算法,即A*算法也使用了启发式搜索的思想,由于这个算法比较复杂,我将单独开一篇文章讲述这种算法。
都看到这里啦,觉得还不错的同学点赞关注支持一下吧,万分感谢!!