最大独立集求解
2015-11-17 17:14
155 查看
定义:
独立集:在一个图中,找到一个集合包含的所有点相互之间都不存在连边
最大独立集:在所有独立集中包含元素个数最多的独立集
之前只是知道二分图的最大独立集 = 总点数-最大匹配数
但是一般无向图的情况下求解就不能这样了
换个角度思考,其实求最大独立集也是相当于建立一个相反图(把当前的边都去掉,添加上之前不被选中的边)
就变成求修改之后的最大完全图的点的个数了,因为我们要保证选到的点之间不存在任何相连的边,那么图反过来之后,选到的点两两之间就必然
存在边,否则说明之前的图是存在边的,也就是两个点不能全选中,而这样得到的就是完全图
而我们求点数最多的那个,也就是最大完全图,也即最大团
最近学习了一下这类问题的求解方式,这可以看做是一类搜索问题,不断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就是一道这个的裸题,只是每次记录了最优解要取到的点而已
独立集:在一个图中,找到一个集合包含的所有点相互之间都不存在连边
最大独立集:在所有独立集中包含元素个数最多的独立集
之前只是知道二分图的最大独立集 = 总点数-最大匹配数
但是一般无向图的情况下求解就不能这样了
换个角度思考,其实求最大独立集也是相当于建立一个相反图(把当前的边都去掉,添加上之前不被选中的边)
就变成求修改之后的最大完全图的点的个数了,因为我们要保证选到的点之间不存在任何相连的边,那么图反过来之后,选到的点两两之间就必然
存在边,否则说明之前的图是存在边的,也就是两个点不能全选中,而这样得到的就是完全图
而我们求点数最多的那个,也就是最大完全图,也即最大团
最近学习了一下这类问题的求解方式,这可以看做是一类搜索问题,不断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就是一道这个的裸题,只是每次记录了最优解要取到的点而已
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; #define N 105 bool mp ; int T , n , k; int dp , ans , tmp , ret , mx , cnt; int _stack ; void build(int k) { memset(mp , 0 , sizeof(mp)); for(int i=1 ; i<=n ; i++) mp[i][i] = true; for(int i=0 ; i<k ; i++){ int a , b; scanf("%d%d" , &a , &b); mp[a][b] = true; } } void dfs(int u , int num , int step) { if(num == 0){ if(mx<step){ mx = step; if(step>ret) for(int i=1 ; i<=step ; i++) ans[i] = tmp[i]; } return; } for(int i=0 ; i<num ; i++){ int v = _stack[u][i]; //two methods of cut the node if(step+dp[v]<=mx) continue; if(step+n-v+1<=mx) continue; //从stack中能访问到v说明,v和之前所有点都有连边的,只要重新更新stack中的数据就可以了 int cnt = 0; for(int j=i+1 ; j<num ; j++){ if(!mp[v][_stack[u][j]]) _stack[v][cnt++] = _stack[u][j]; } tmp[step+1] = v; dfs(v , cnt , step+1); } } int main() { // freopen("a.in" , "r" , stdin); scanf("%d" , &T); while(T--){ scanf("%d%d" , &n , &k); build(k); ret = 0; //init for(int i=n ; i>=1 ; i--){ cnt = 0 , mx = 1; for(int j=i+1 ; j<=n ; j++){ if(!mp[i][j]) _stack[i][cnt++] = j; } tmp[1] = i; dfs(i , cnt , 1); dp[i] = mx; ret = max(ret , dp[i]); } printf("%d\n" , ret); for(int i=1 ; i<=ret ; i++){ if(i<ret) printf("%d " , ans[i]); else printf("%d\n" , ans[i]); } } return 0; }
相关文章推荐
- axure淘宝购买记录Project 2013软件+
- 字体sp转px
- 【C语言】【面试题】使用main函数的参数,实现一个整数计算机,程序可以接受三个参数
- java程序员第十四课 -JSP技术、JavaBean知识和EL表达式(重点)-JSP的开发模式,注册和登陆的案例
- quartz实现动态定时任务
- linux进程间的通信--信号量同步
- equals getClass
- sqlite第三方类库:FMDB使用
- JS :3秒后自动跳转功能
- Really simple SSH proxy (SOCKS5)
- PEAR DB 事务相关
- android 状态栏和导航栏(status and navigation bars)
- 数据结构(Java)——迭代器Iterator
- jobserver和日志聚集aggregation
- linux--use用法
- django 1.8 出现 TemplateDoesNotExist 错误
- 一些输入的控制(待优化)
- JDK自带工具列表
- (转)Smarty Foreach 使用说明
- HDU 2795 Billboard 线段树