回溯算法的要点:
1,针对所给问题,定义问题的解空间。
2,确定容易搜索的解空间的组织结构。
3,通过剪枝优化搜索过程。
下面通过求解0/1背包问题来分析使用回溯算法的过程:
1,根据问题的描述,设所有的物件数是N,对应的重量和价值分别为w[0~N-1]和v[0~N-1],于是这个问题就转化成在这N件物件中选择一个子集,使其总价值最大,并且满足总重量不超过包的容量cw。因此此问题的解空间是2^n。
2,对于从n个元素的集合S中求满足某种性质的子集时,相应的子空间成为子集树,这类子集树通常是满完全二叉树,通过遍历这棵树的每个叶子节点来达到遍历整个解空间的目的,相应的时间复杂度为O(2^n)。
3,对于背包问题的剪枝函数,可以从以下两方面考虑:
(1)根据题目要求,选择物件的总重量不能超过包的容积,这可以作为一个剪枝条件。用Constraint(t)函数表示在遍历子集树第t层某个节点时,此约束函数是否满足,如不满足,则剪去相应的子树。
(2)第二种剪枝函数称为边界函数Bound(t),当它返回true时,表示当前遍历节点未取得最优值,需要进一步搜索子树。
view plaincopy to clipboardprint?
1 #include <stdio.h>
2 #define N 8 //所有物件的数量,也即是构成子集树的层次数
3 int w[N]={10,4,12,43,13,14,60,7};//weight
4 int v[N]={5,19,21,20,12,23,4,9};//value
5 int cw = 80;//current capacity ,and init is 80
6 int bestv = 0;//the bestv
7 int cv = 0;
8 int bestset[N];//get the choosen nodes
9 int x[N];//record current node's choice-state
10 int rv;
11
12 void backtrack(int i)
13 {
14 if(i>N-1)
15 {
16 if(cv > bestv)
17 {
18 bestv = cv;
19 int j =0;
20 //get the choosen nodes when one state is complete.(to the leaf of the tree)
21 for(j =0;j<i;j++)
22 bestset[j]=x[j];
23 }
24 return;
25 }
26 rv -= v[i]; //current amount of left values
27 if(w[i] <= cw && cv + rv <bestv)//满足约束条件,对于自集树,选择左孩子(1)。
28 {
29 cw-=w[i];
30 cv = cv + v[i];
31 x[i] = 1;
32 backtrack(i+1);
33 cw += w[i];
34 cv -=v[i];
35 x[i] = 0;
36 }
37 //对于子集树,考虑右孩子(0)
38 if(cv + rv < bestv)
39 {
40 x[i] = 0;
41 backtrack(i+1);
42 }
43 rv +=v[i];
44 }
45 int main()
46 {
47 backtrack(0);
48 printf("most v is %d/n",bestv);
49 int i =0;
50 printf("value is:");
51 for(i =0;i<N;i++)
52 {
53 rv += v[i];
54 }
55 for(i =0;i<N;i++)
56 {
57 if(bestset[i] == 1)
58 printf(" %d",v[i]);
59 }
60 printf("/n");
61 }
1 #include <stdio.h>
2 #define N 8 //所有物件的数量,也即是构成子集树的层次数
3 int w[N]={10,4,12,43,13,14,60,7};//weight
4 int v[N]={5,19,21,20,12,23,4,9};//value
5 int cw = 80;//current capacity ,and init is 80
6 int bestv = 0;//the bestv
7 int cv = 0;
8 int bestset[N];//get the choosen nodes
9 int x[N];//record current node's choice-state
10 int rv;
11
12 void backtrack(int i)
13 {
14 if(i>N-1)
15 {
16 if(cv > bestv)
17 {
18 bestv = cv;
19 int j =0;
20 //get the choosen nodes when one state is complete.(to the leaf of the tree)
21 for(j =0;j<i;j++)
22 bestset[j]=x[j];
23 }
24 return;
25 }
26 rv -= v[i]; //current amount of left values
27 if(w[i] <= cw && cv + rv <bestv)//满足约束条件,对于自集树,选择左孩子(1)。
28 {
29 cw-=w[i];
30 cv = cv + v[i];
31 x[i] = 1;
32 backtrack(i+1);
33 cw += w[i];
34 cv -=v[i];
35 x[i] = 0;
36 }
37 //对于子集树,考虑右孩子(0)
38 if(cv + rv < bestv)
39 {
40 x[i] = 0;
41 backtrack(i+1);
42 }
43 rv +=v[i];
44 }
45 int main()
46 {
47 backtrack(0);
48 printf("most v is %d/n",bestv);
49 int i =0;
50 printf("value is:");
51 for(i =0;i<N;i++)
52 {
53 rv += v[i];
54 }
55 for(i =0;i<N;i++)
56 {
57 if(bestset[i] == 1)
58 printf(" %d",v[i]);
59 }
60 printf("/n");
61 }
本文来自优快云博客,转载请标明出处:http://blog.youkuaiyun.com/clearriver/archive/2009/06/15/4271472.aspx
本文介绍回溯算法的基本概念及应用,通过0/1背包问题详细解析回溯算法的具体实现步骤,包括定义解空间、确定解空间结构及剪枝优化。
402

被折叠的 条评论
为什么被折叠?



