最大团问题

来源:互联网 发布:南山软件产业基地图片 编辑:程序博客网 时间:2024/06/06 05:50

百度上的定义:
http://baike.baidu.com/item/%E6%9C%80%E5%A4%A7%E5%9B%A2%E9%97%AE%E9%A2%98

简单的讲最大团就是最大完全子图

一般做法就是dfs+剪枝
可参考这篇博客:
http://www.cnblogs.com/zhj5chengfeng/p/3224092.html

下面介绍几个例题:
1、第一道裸题:ZOJ 1492 Maximum Clique

给了一个最多包含 50 个点的无向图,让求这个图中最大团所包含的的点的数量
直接套模板就行。。

#include <set>#include <map>#include <queue>#include <vector>#include <math.h>#include <iostream>#include <stdio.h>#include <algorithm>#include <string.h>using  namespace  std;#define ff first#define ss second#define pb push_back#define ll long long#define mod 1000000007#define ull unsigned long long#define mst(ss,b) memset(ss,b,sizeof(ss));#define pl(x) cout << #x << "= " << x << endl;const int inf = 0x3f3f3f3f;const int N = 1e5+5;struct node{    static const int N = 60; //可修改    bool G[N][N]; //初始化    int n, Max[N], Alt[N][N], ans;    bool dfs(int cur, int tol){        if(cur == 0){            if(tol>ans){  // 用一个更大的极大团替代原有的极大团                 ans = tol;                return 1;            }            return 0;        }        for(int i=0; i<cur; i++){            if(cur-i+tol <= ans)return 0;            int u = Alt[tol][i];            if(Max[u]+tol <= ans)return 0;            int nxt = 0;            for(int j=i+1; j<cur; j++)                if(G[u][Alt[tol][j]])Alt[tol+1][nxt++] = Alt[tol][j];            if(dfs(nxt, tol+1)) return 1;        }        return 0;    }    int max_clique(){        ans = 0;        mst(Max, 0);        for(int i=n-1; i>=0; i--){ // 先找一个点,把与它相连的点加进来,这些点可能构成最大团,然后dfs判断出一个临时极大团            int cur = 0;            for(int j=i+1; j<n; j++)if(G[i][j])Alt[1][cur++] = j;            dfs(cur, 1);             Max[i] = ans;        }        return ans;    }};node mc;int  main(){    while(~scanf("%d", &mc.n)){        if(!mc.n)break;        for(int i=0; i<mc.n; i++)            for(int j=0; j<mc.n; j++)                scanf("%d", &mc.G[i][j]); //G[u][v]表示u,v之间是否有边        printf("%d\n", mc.max_clique());    }    return 0;}

2.一般无向图最大独立集的题目:POJ 1419 Graph Coloring

给了一个有 n 个点 m 条边的无向图,要求用黑、白两种色给图中顶点涂色,相邻的两个顶点不能涂成黑色,求最多能有多少顶点涂成黑色。图中最多有 100 个点

从相邻的点不能够涂上相同的颜色我们可以得出该题的实质就是要求一个最大的点独立集,而求一个图的点独立集如果所给的图是一棵树的话,就可以通过拆点转化为二分图来解了,由于给定的图很可能成环,因此化作二分图的做法在这里不再适应。另一个对应的问题就是通过对原图建一个反图,然后对反图做一个最大团的求解,最大团保证了是反图中的最大完全子集,任何两个元素之间都有边相连,反应在原图中则是任意两两之间不存在边,也就是两两不相邻,这刚好契合的题意。

ps:这题需要记录顶点

#include <set>#include <map>#include <stack>#include <queue>#include <string>#include <vector>#include <math.h>#include <stdio.h>#include <stdlib.h>#include <iostream>#include <string.h>#include <algorithm>using  namespace  std;#define ff first#define ss second#define pb push_back#define ll long long#define mod 1000000007#define ull unsigned long long#define mst(ss,b) memset(ss,b,sizeof(ss));#define pl(x) cout << #x << "= " << x << endl;const int inf = 0x3f3f3f3f;const int N = 1e5+5;// **** 表示记录顶点的部分struct node{    static const int N = 105; //可修改    bool G[N][N]; // 点标号从0开始 Ķ    int n, Max[N], Alt[N][N], ans;    int tmp[N], ret[N]; // ****    bool dfs(int cur, int tol){        if(cur == 0){            if(tol>ans){                memcpy(ret, tmp, sizeof tmp); // **** 用一个更大的极大团替代原有的极大团                 ans = tol;                return 1;            }            return 0;        }        for(int i=0; i<cur; i++){            if(cur-i+tol <= ans)return 0;            int u = Alt[tol][i];            if(Max[u]+tol <= ans)return 0;            int nxt = 0;            for(int j=i+1; j<cur; j++)                if(G[u][Alt[tol][j]])Alt[tol+1][nxt++] = Alt[tol][j];            tmp[tol+1] = u;//  ****             if(dfs(nxt, tol+1)) return 1;        }        return 0;    }    int max_clique(){        ans = 0;        mst(Max, 0);        for(int i=n-1; i>=0; i--){            int cur = 0;            tmp[1] = i;//  ****            for(int j=i+1; j<n; j++)if(G[i][j])Alt[1][cur++] = j;            dfs(cur, 1);            Max[i] = ans;        }        return ans;    }};node mc;int  main(){    int T, m;    scanf("%d", &T);    while(T--){        mst(mc.G, true);        scanf("%d%d", &mc.n, &m);        for(int i=1; i<=m; i++){            int u, v;            scanf("%d%d", &u, &v);            mc.G[u-1][v-1] = mc.G[v-1][u-1] = 0;        }        int ans = mc.max_clique();        printf("%d\n", ans);        for(int i=1; i<=ans; i++){            printf("%d%c", mc.ret[i]+1, i==ans?'\n':' '); //注意输出标号是否+1        }    }    return 0;}

3.一道经典的染色问题:POJ 1129 Channel Allocation

最多 26 广播电台…我还是讲抽象之后的题意吧:最多26个点的无向图,要求相邻的节点不能染成同一个颜色,问最少需要多少颜色染完所有的顶点

利用上面提到的结论:图的染色问题中,最少需要的颜色的数量=最大团点的数量,建图,跑最大团即可

直接爆搜,理论复杂度是O(n*n*m)

#include <set>#include <map>#include <queue>#include <vector>#include <math.h>#include <iostream>#include <stdio.h>#include <algorithm>#include <string.h>using  namespace  std;#define ff first#define ss second#define pb push_back#define ll long long#define mod 1000000007#define ull unsigned long long#define mst(ss,b) memset(ss,b,sizeof(ss));#define pl(x) cout << #x << "= " << x << endl;const int inf = 0x3f3f3f3f;const int N = 25;int n, m;bool mp[N][N], fg;int col[N];void dfs(int x, int tol){//当前点 最大色彩数    if(fg)return ;    if(x == n+1){        fg = 1;        return ;    }    for(int i=1; i<=min(x, tol); i++){        col[x] = i;        bool ok = 1;        for(int j=1; j<x; j++){            if(mp[x][j] && col[x] == col[j]){                ok = 0;                break;            }        }        if(ok)dfs(x+1, tol);    }}char s[30];int  main(){    while(~scanf("%d", &n), n){        mst(mp, 0);        for(int i=1; i<=n; i++){           scanf("%s", s);           for(int j=2; s[j]; j++)                mp[s[0]-'A'+1][s[j]-'A'+1] = 1;        }        fg = 0;        for(int i=1; i<=n; i++){            dfs(1, i);            if(fg){                if(i == 1)printf ("1 channel needed.\n");                else printf ("%d channels needed.\n", i);                break;            }        }    }    return 0;}

以下代码作废:

#include <set>#include <map>#include <stack>#include <queue>#include <string>#include <vector>#include <math.h>#include <stdio.h>#include <stdlib.h>#include <iostream>#include <string.h>#include <algorithm>using  namespace  std;#define ff first#define ss second#define pb push_back#define ll long long#define mod 1000000007#define ull unsigned long long#define mst(ss,b) memset(ss,b,sizeof(ss));#define pl(x) cout << #x << "= " << x << endl;const int inf = 0x3f3f3f3f;const int N = 1e5+5;struct node{    static const int N = 27;    bool G[N][N];    int n, Max[N], Alt[N][N], ans;    bool dfs(int cur, int tol){        if(cur == 0){            if(tol>ans){                ans = tol;                return 1;            }            return 0;        }        for(int i=0; i<cur; i++){            if(cur-i+tol <= ans)return 0;            int u = Alt[tol][i];            if(Max[u]+tol <= ans)return 0;            int nxt = 0;            for(int j=i+1; j<cur; j++)                if(G[u][Alt[tol][j]])Alt[tol+1][nxt++] = Alt[tol][j];            if(dfs(nxt, tol+1)) return 1;        }        return 0;    }    int max_clique(){        ans = 0;        mst(Max, 0);        for(int i=n-1; i>=0; i--){            int cur = 0;            for(int j=i+1; j<n; j++)if(G[i][j])Alt[1][cur++] = j;            dfs(cur, 1);            Max[i] = ans;        }        return ans;    }};node mc;int  main(){    while(~scanf("%d", &mc.n), mc.n){        char s[30];        mst(mc.G, 0);        for(int i=1; i<=mc.n; i++){            scanf("%s", s);            for(int j=2; s[j]; j++){                int u = s[0] - 'A', v = s[j] - 'A';                mc.G[u][v] = 1;            }        }        int ans = mc.max_clique();        if(ans == 1)printf("%d channel needed.\n", ans);        else printf("%d channels needed.\n", ans);    }    return 0;}
0 0
原创粉丝点击