码迷,mamicode.com
首页 > 其他好文 > 详细

最大独立集求解

时间:2015-11-17 18:32:55      阅读:185      评论:0      收藏:0      [点我收藏+]

标签:

定义:

独立集:在一个图中,找到一个集合包含的所有点相互之间都不存在连边

最大独立集:在所有独立集中包含元素个数最多的独立集

 

之前只是知道二分图的最大独立集 = 总点数-最大匹配数

但是一般无向图的情况下求解就不能这样了

 

换个角度思考,其实求最大独立集也是相当于建立一个相反图(把当前的边都去掉,添加上之前不被选中的边)

就变成求修改之后的最大完全图的点的个数了,因为我们要保证选到的点之间不存在任何相连的边,那么图反过来之后,选到的点两两之间就必然

存在边,否则说明之前的图是存在边的,也就是两个点不能全选中,而这样得到的就是完全图

而我们求点数最多的那个,也就是最大完全图,也即最大团

 

最近学习了一下这类问题的求解方式,这可以看做是一类搜索问题,不断dfs搜索找到最优解

这样很容易看出 这是一个NP问题,复杂度也是 O(2^n)的

 

 所以优秀的剪枝是非常必要的

定义dp[i] 是 i ~ N 这些点所能构成的最大团的点数

那么我们就可以倒过来逐个算出dp[]值

对于前面的dp[]值就要利用之前算出来的值来剪枝

我们这里一个个从小到大添加节点,保证从当前出发添加进来的节点dp值已经求得

例如当前添加了 v , 之前有了 t 个点了

那么就可以用

t+dp[v] <=mx

t+N-t+1<=mx

来剪枝了(这个仔细想一下就知道了)

我们用一个_stack[][]数组记录能够扩展的节点,也就是这个数组中的点和之前取到的点每一个都存在连边,所以添加进来可以直接构成完全图

我们只要每次再添加节点后更新这个数组就可以了

因为是递归求解了,防止更新了会在回溯时出错,那么就讲数组定成两维的,第一维表示当前集合最大的点就可以直接用了

int cnt = 0;
for(int j=i+1 ; j<num ; j++){
  if(!mp[v][_stack[u][j]]) _stack[v][cnt++] = _stack[u][j];
}

 

然后POJ1419就是一道这个的裸题,只是每次记录了最优解要取到的点而已

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 using namespace std;
 5 #define N 105
 6 bool mp[N][N];
 7 int T , n , k;
 8 int dp[N] , ans[N] , tmp[N] , ret , mx , cnt;
 9 int _stack[N][N];
10 
11 void build(int k)
12 {
13     memset(mp , 0 , sizeof(mp));
14     for(int i=1 ; i<=n ; i++) mp[i][i] = true;
15     for(int i=0 ; i<k ; i++){
16         int a , b;
17         scanf("%d%d" , &a , &b);
18         mp[a][b] = true;
19     }
20 }
21 
22 void dfs(int u , int num , int step)
23 {
24     if(num == 0){
25         if(mx<step){
26             mx = step;
27             if(step>ret) for(int i=1 ; i<=step ; i++) ans[i] = tmp[i];
28         }
29         return;
30     }
31 
32     for(int i=0 ; i<num ; i++){
33         int v = _stack[u][i];
34         //two methods of cut the node
35         if(step+dp[v]<=mx) continue;
36         if(step+n-v+1<=mx) continue;
37         //从stack中能访问到v说明,v和之前所有点都有连边的,只要重新更新stack中的数据就可以了
38         int cnt = 0;
39         for(int j=i+1 ; j<num ; j++){
40             if(!mp[v][_stack[u][j]]) _stack[v][cnt++] = _stack[u][j];
41         }
42         tmp[step+1] = v;
43         dfs(v , cnt , step+1);
44     }
45 }
46 
47 int main()
48 {
49   //  freopen("a.in" , "r" , stdin);
50     scanf("%d" , &T);
51     while(T--){
52         scanf("%d%d" , &n , &k);
53         build(k);
54         ret = 0; //init
55         for(int i=n ; i>=1 ; i--){
56             cnt = 0 , mx = 1;
57             for(int j=i+1 ; j<=n ; j++){
58                 if(!mp[i][j]) _stack[i][cnt++] = j;
59             }
60             tmp[1] = i;
61             dfs(i , cnt , 1);
62             dp[i] = mx;
63             ret = max(ret , dp[i]);
64         }
65         printf("%d\n" , ret);
66         for(int i=1 ; i<=ret ; i++){
67             if(i<ret) printf("%d " , ans[i]);
68             else printf("%d\n" , ans[i]);
69         }
70     }
71     return 0;
72 }

 

最大独立集求解

标签:

原文地址:http://www.cnblogs.com/CSU3901130321/p/4972300.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!