定义:
独立集:在一个图中,找到一个集合包含的所有点相互之间都不存在连边
最大独立集:在所有独立集中包含元素个数最多的独立集
之前只是知道二分图的最大独立集 = 总点数-最大匹配数
但是一般无向图的情况下求解就不能这样了
换个角度思考,其实求最大独立集也是相当于建立一个相反图(把当前的边都去掉,添加上之前不被选中的边)
就变成求修改之后的最大完全图的点的个数了,因为我们要保证选到的点之间不存在任何相连的边,那么图反过来之后,选到的点两两之间就必然
存在边,否则说明之前的图是存在边的,也就是两个点不能全选中,而这样得到的就是完全图
而我们求点数最多的那个,也就是最大完全图,也即最大团
最近学习了一下这类问题的求解方式,这可以看做是一类搜索问题,不断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 }