最大团,最大独立集

来源:互联网 发布:国家网络安全法 编辑:程序博客网 时间:2024/06/05 20:53

最大团,最大独立集

最大独立集:一个图中最大的互相没有边相连的点集。

结论:原图的最大独立集等于补图的最大团

经典的NP完全问题,只有暴力解,时间复杂度O(n2^n)

对于无向图来说

所谓最大团, 其实就是找一个最大完全子图,最大就是包含的点最多.

而最大独立集== 补图的最大团

这里使用深度优先搜索实现,对于每一个结点,考虑要与不要两种状态,则问题构成一个子集树,本质上与01背包一样,只不过多了联通性的判断

// 最大独立集的做法,求出最大独立集,并且打印方案
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <algorithm>
#include<vector> 
using namespace std; 
vector<vector<int> > G;
int n, m;
int color[123];
vector<int> rec;
int maxnum;
void dfs(int u,int _count) {
    if (_count > maxnum) {//更新答案
        maxnum = _count;
        rec.clear();
        for (int i = 1;i <= n;++i) {
            if (color[i]) rec.push_back(i);
        }
    }
    if (u == n + 1) return ;
    //用于判断是否可以染成黑色
    bool ok = true;
    for (int i = 0;i < G[u].size();++i) {
        if (color[G[u][i]]) ok = false;
    }
 
    if (ok) {//u节点可以染成黑色
        color[u] = 1;
        dfs(u + 1, _count + 1);
        color[u] = 0;
    }
    dfs(u + 1, _count);//u染成白色->跳过
}
int main(int argc, const char * argv[])
{
    int t, u, v;
    cin >> t;
    while(t--) {
        scanf("%d%d", &n, &m);
        G.clear();
        G.resize(n + 2);
        while(m--) {
            scanf("%d%d", &u, &v);
            G[u].push_back(v);
            G[v].push_back(u);
        }
        memset(color, 0,sizeof color);
        maxnum = 0;
        dfs(1, 0);
        printf("%d\n", maxnum);
        for (int i = 0;i < rec.size();++i)
            printf("%d%c", rec[i], i == maxnum - 1?'\n':' ');
    }
    return 0;
}
//用最大团求最大独立子集 
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <algorithm>
using namespace std;
 
int N, M, mp[105][105];
int ret, cnt, opt[105], st[105];
 
void dfs(int x) {
    if (x > N) { // 如果枚举了所有的节点 
        ret = cnt;
        memcpy(opt, st, sizeof (st)); // 用一个更大的极大团替代原有的极大团 
        return;
    }
    int flag = true;
    for (int i = 1; i < x; ++i) { // 检测新加入的点是否到团中的其他节点都存在一条边 
        if (st[i] && !mp[i][x]) {
            flag = false;
            break;
        }
    }
    if (flag) { // 如果该节点满足在这个团中 
        st[x] = 1, ++cnt; // 该节点被加入到完全子图中去
        dfs(x + 1);
        st[x] = 0, --cnt;
    }
    if (cnt+N-x > ret) { // 跳过x节点进行搜索同时进行一个可行性判定 
        dfs(x + 1);
    }
}
 
int main() {
    int T, x, y;
    scanf("%d", &T);
    while (T--) {
        ret = cnt = 0;
        scanf("%d %d", &N, &M);
        memset(st, 0, sizeof (st));
        for (int i = 0; i < 105; ++i) {
            fill(mp[i], mp[i]+105, 1);
        }
        while (M--) {
            scanf("%d %d", &x, &y);
            mp[x][y] = mp[y][x] = 0;
        }
        dfs(1);
        printf("%d\n", ret);
        for (int i = 1, j = 0; i <= N; ++i) {
            if (opt[i]) {
                printf(j == 0 ? "%d" : " %d", i);
                ++j;
            }    
        }
        puts("");
    }
    return 0;    
}
原创粉丝点击