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 }
posted @ 2014-07-18 17:30  Naturain  阅读(254)  评论(0编辑  收藏  举报