Uva--10160(回溯,剪枝)

2014-07-18 17:10:26

题意:也算是一个经典的回溯问题。题意不再赘述,来讲讲剪枝:

(1)首先采用邻接表的方式保存图的信息,并对每个点的表进行从大到小的排序。(因为是从第一个点开始DFS,从大到小排序可以使优先考虑后面的点,避免每次都遍历已经考虑的点,以增加效率)

(2)如果当前设立的St数已经超过当前所算的最小值tmin,直接return,后面的已经没有意义。

(3)如果之前已经考虑的点没有被覆盖,而且在当前点及其之后的点也没有与之相连的,那么这个点在之后也不会覆盖,直接return。

 1 #include <cstdio>
 2 #include <iostream>
 3 #include <cstring>
 4 #include <cmath>
 5 #include <algorithm>
 6 using namespace std;
 7 
 8 int tmin,n,m;
 9 int g[36][36],used[36],sum[36];
10 
11 void Dfs(int cur,int num,int cnt){ //cur:当前处理点,num:St数,cnt:覆盖的点数
12     if(num >= tmin) //当前操作数超当前最小值,剪枝
13         return;
14     if(cnt >= n){
15         tmin = min(tmin,num);
16         return;
17     }
18     if(cur > n) //已覆盖所有点
19         return;
20     for(int i = 1; i < cur; ++i) //考虑之前的点,且在cur之后没有连接点,剪枝
21         if(used[i] == 0 && g[i][0] < cur)
22             return;
23     int flag = 0;
24     //cur这个点放St
25     for(int i = 0; i < sum[cur]; ++i){
26         if(used[g[cur][i]] == 0) //存在未覆盖的点
27             ++flag;
28         used[g[cur][i]]++; 
29     }
30     if(flag) //若存在未覆盖的点
31         Dfs(cur + 1,num + 1,cnt + flag);
32     //cur这个点不放St
33     for(int i = 0; i < sum[cur]; ++i)
34         used[g[cur][i]]--;
35     Dfs(cur + 1,num,cnt);
36 }
37 
38 int main(){
39     int a,b;
40     while(scanf("%d%d",&n,&m) == 2){
41         if(!n && !m) break;
42         memset(g,0,sizeof(g));
43         memset(sum,0,sizeof(sum));
44         while(m--){
45             scanf("%d%d",&a,&b);
46             g[a][sum[a]++] = b;
47             g[b][sum[b]++] = a;
48         }
49         for(int i = 1; i <= n; ++i){
50             g[i][sum[i]++] = i; //之所以要放自己,是因为放了St后自己也被覆盖
51             sort(g[i],g[i] + sum[i],greater<int>());
52         }
53         tmin = n;
54         Dfs(1,0,0);
55         printf("%d\n",tmin);
56     }
57     return 0;
58 }

转载于:https://www.cnblogs.com/naturepengchen/articles/3853995.html

0-1背包问题是一个经典的组合优化问题,目标是在给定的一组物品中选择一些物品放入背包,使得物品的总重量不超过背包的容量,同时总价值最大化。回溯法是一种解决0-1背包问题的方法。 回溯法的基本思想是通过递归的方式,穷举所有可能的解,并通过剪枝操作来减少不必要的计算。具体步骤如下: 1. 定义一个递归函数backtrack,该函数接受四个参数:当前物品的索引i,当前背包的重量cw,当前背包的价值cv,以及剩余物品的重量和价值数组。 2. 在backtrack函数中,首先判断递归终止条件。如果当前物品的索引i等于物品个数n,或者当前背包的重量cw大于背包容量c,则返回当前背包的价值cv。 3. 如果递归没有终止,那么有两种情况需要考虑: - 选择当前物品放入背包:将当前物品的重量和价值加到cw和cv上,并递归调用backtrack函数,更新当前物品的索引i为i+1。 - 不选择当前物品放入背包:直接递归调用backtrack函数,更新当前物品的索引i为i+1。 4. 在每次递归调用后,比较选择和不选择两种情况的结果,返回价值较大的那个。 5. 最后,调用backtrack函数,传入初始参数i=0,cw=0,cv=0,得到0-1背包问题的最优解和最优值。 下面是使用回溯法解决0-1背包问题的示例代码: ```python def backtrack(i, cw, cv, weight, value, n, c): if i == n or cw == c: return cv if cw + weight[i] <= c: choose = backtrack(i+1, cw+weight[i], cv+value[i], weight, value, n, c) else: choose = 0 not_choose = backtrack(i+1, cw, cv, weight, value, n, c) return max(choose, not_choose) weight = [2, 3, 4, 5] value = [3, 4, 5, 6] n = len(weight) c = 8 max_value = backtrack(0, 0, 0, weight, value, n, c) print("The maximum value is:", max_value) ``` 该代码中,weight和value分别表示物品的重量和价值,n表示物品个数,c表示背包容量。运行代码后,会输出0-1背包问题的最优值。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值