zoukankan      html  css  js  c++  java
  • 最大团问题

    讲解就在这里http://www.cnblogs.com/zhj5chengfeng/archive/2013/07/29/3224092.html

    说的很清晰,列举的题目也比较简单

    重要的几个结论

    1、最大团点的数量=补图中最大独立集点的数量

    2、二分图中,最大独立集点的数量+最小覆盖点的数量=整个图点的数量

    3、二分图中,最小覆盖点的数量=最大匹配的数量

    4、图的染色问题中,最少需要的颜色的数量=最大团点的数量

    模板

    ZOJ 1492 MAXClique

    给了一个最多包含 50 个点的无向图,让求这个图中最大团所包含的的点的数量

    直接按照上面所讲的 DFS 过程做就行

    #include <map>
    #include <set>
    #include <list>
    #include <cmath>
    #include <ctime>
    #include <deque>
    #include <stack>
    #include <queue>
    #include <cctype>
    #include <cstdio>
    #include <string>
    #include <vector>
    #include <climits>
    #include <cstdlib>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #define LL unsigned long long
    #define PI 3.1415926535897932626
    using namespace std;
    int gcd(int a, int b) {return b == 0 ? a : gcd(b, a % b);}
    const int MAXN = 70;
    struct Max_Clique
    {
        int G[MAXN][MAXN];
        int N,MAX[MAXN],Alt[MAXN][MAXN],ans;
    
        bool dfs(int cur,int tot)
        {
            if (cur == 0)
            {
                if (tot > ans)
                {
                    ans = tot;
                    return true;
                }
                return false;
            }
            for (int i = 0 ; i < cur ; i++)
            {
                if (cur - i + tot <= ans) return false;
                int u = Alt[tot][i];
                if (MAX[u] + tot <= ans) return false;
                int nxt = 0;
                for (int j = i + 1 ; j < cur ; j++)
                    if (G[u][Alt[tot][j]]) Alt[tot + 1][nxt++] = Alt[tot][j];
                if (dfs(nxt,tot + 1)) return true;
            }
            return false;
        }
    
        int MaxClique()
        {
            ans = 0;
            memset(MAX,0,sizeof(MAX));
            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;
        }
    }slover;
    
    int main()
    {
        while (scanf("%d",&slover.N) != EOF)
        {
            if (slover.N == 0) break;
            for (int i = 0 ; i < slover.N ; i++)
                for (int j = 0 ; j < slover.N ; j++)
                scanf("%d",&slover.G[i][j]);
            printf("%d
    ",slover.MaxClique());
        }
        return 0;
    }
    View Code


    POJ 3692 Kindergarten

    二分图中补图的最大独立集==最大团

    #include <map>
    #include <set>
    #include <list>
    #include <cmath>
    #include <ctime>
    #include <deque>
    #include <stack>
    #include <queue>
    #include <cctype>
    #include <cstdio>
    #include <string>
    #include <vector>
    #include <climits>
    #include <cstdlib>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #define LL long long
    #define PI 3.1415926535897932626
    using namespace std;
    int gcd(int a, int b) {return a % b == 0 ? b : gcd(b, a % b);}
    const int MAXN = 410;
    bool used[MAXN];
    int linker[MAXN];
    int g[MAXN][MAXN];
    int G,B,M;
    
    bool dfs(int u)
    {
        for (int i = 1 ; i <= B ; i++)
        {
            if (g[u][i] == 0 && !used[i])
            {
                used[i] = true;
                if (linker[i] == -1 || dfs(linker[i]))
                {
                    linker[i] = u;
                    return true;
                }
            }
        }
        return false;
    }
    
    int calcu()
    {
        int ret = 0;
        memset(linker,-1,sizeof(linker));
        for (int i = 1 ; i <= G ; i++)
        {
            memset(used,false,sizeof(used));
            if (dfs(i)) ret++;
        }
        return ret;
    }
    
    int main()
    {
        int kase = 1;
        while (scanf("%d%d%d",&G,&B,&M) != EOF)
        {
            if (G == 0 && B == 0 && M == 0) break;
            memset(g,0,sizeof(g));
            while (M--)
            {
                int u,v;
                scanf("%d%d",&u,&v);
                g[u][v] = 1;
            }
            printf("Case %d: ",kase++);
            printf("%d
    ",G + B - calcu());
        }
        return 0;
    }
    View Code

    HDU 3585 maximum shortest distance
    给了平面上 n 个点,要求选出 k 个点来,使得这 k 个点中,距离最近的两个点的距离最大。n 最大为50

    二分距离大于距离建图求最短就行了

    #include <map>
    #include <set>
    #include <list>
    #include <cmath>
    #include <ctime>
    #include <deque>
    #include <stack>
    #include <queue>
    #include <cctype>
    #include <cstdio>
    #include <string>
    #include <vector>
    #include <climits>
    #include <cstdlib>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #define LL unsigned long long
    #define PI 3.1415926535897932626
    using namespace std;
    int gcd(int a, int b) {return b == 0 ? a : gcd(b, a % b);}
    const int MAXN = 70;
    const double eps = 1e-3;
    const double INF = 1e15;
    struct Max_Clique
    {
        int G[MAXN][MAXN];
        int N,MAX[MAXN],Alt[MAXN][MAXN],ans;
    
        bool dfs(int cur,int tot)
        {
            if (cur == 0)
            {
                if (tot > ans)
                {
                    ans = tot;
                    return true;
                }
                return false;
            }
            for (int i = 0 ; i < cur ; i++)
            {
                if (cur - i + tot <= ans) return false;
                int u = Alt[tot][i];
                if (MAX[u] + tot <= ans) return false;
                int nxt = 0;
                for (int j = i + 1 ; j < cur ; j++)
                    if (G[u][Alt[tot][j]]) Alt[tot + 1][nxt++] = Alt[tot][j];
                if (dfs(nxt,tot + 1)) return true;
            }
            return false;
        }
    
        int MaxClique()
        {
            ans = 0;
            memset(MAX,0,sizeof(MAX));
            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;
        }
    }slover;
    
    struct point
    {
        double x,y;
    }src[MAXN];
    int N,K;
    
    double dis(point a,point b)
    {
        return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
    }
    
    bool judge(double mid)
    {
        memset(slover.G,0,sizeof(slover.G));
        for (int i = 0 ; i < N ; i++)
            for (int j = i + 1 ; j < N ; j++)
        {
            double dist = dis(src[i],src[j]);
            if (dist >= mid) slover.G[i][j] = slover.G[j][i] = 1;
        }
        int num = slover.MaxClique();
        if(num >= K)return true;
        return false;
    }
    
    int main()
    {
        while (scanf("%d%d",&N,&K) != EOF)
        {
            for (int i = 0 ; i < N ; i++)scanf("%lf%lf",&src[i].x,&src[i].y);
            slover.N = N;
            double L = 0,R = 500000.0;
            for (int i = 1 ; i <= 50 ; i++)
            {
                double mid = (L + R) / 2.0;
                if (judge(mid)) L = mid;
                else R = mid;
            }
            printf("%.2lf
    ",L);
        }
        return 0;
    }
    View Code

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

    利用结论补图最大独立集等于最大团

    #include <map>
    #include <set>
    #include <list>
    #include <cmath>
    #include <ctime>
    #include <deque>
    #include <stack>
    #include <queue>
    #include <cctype>
    #include <cstdio>
    #include <string>
    #include <vector>
    #include <climits>
    #include <cstdlib>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #define LL unsigned long long
    #define PI 3.1415926535897932626
    typedef long long type;
    using namespace std;
    type gcd(type a, type b) {return b == 0 ? a : gcd(b, a % b);}
    const int MAXN = 110;
    struct Max_Clique
    {
        int G[MAXN][MAXN];
        int N,MAX[MAXN],Alt[MAXN][MAXN],ans;
        int ret[MAXN],tot1;
        int tmp[MAXN],tot2;
    
        void init(int n)
        {
            N = n;
        }
        bool dfs(int cur,int tot)
        {
            if (cur == 0)
            {
                if (tot > ans)
                {
                    ans = tot;
                    for (int i = 1 ; i <= tot ; i++)
                    {
                        ret[i] = tmp[i];
                    }
                    return true;
                }
                return false;
            }
            for (int i = 0 ; i < cur ; i++)
            {
                if (cur - i + tot <= ans) return false;
                int u = Alt[tot][i];
                if (MAX[u] + tot <= ans) return false;
                int nxt = 0;
                for (int j = i + 1 ; j < cur ; j++)
                    if (G[u][Alt[tot][j]]) Alt[tot + 1][nxt++] = Alt[tot][j];
                tmp[tot + 1] = u;
                if (dfs(nxt,tot + 1)) return true;
            }
            return false;
        }
    
        int MaxClique()
        {
            ans = 0;
            memset(MAX,0,sizeof(MAX));
            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;
        }
    }slover;
    
    
    int main()
    {
        int T;
        scanf("%d",&T);
        while (T--)
        {
            int N,M;
            scanf("%d%d",&N,&M);
            slover.init(N);
            for (int i = 0 ; i <= N ; i++) for (int j = 0 ; j <= N ; j++) slover.G[i][j] = 1;
            for (int i = 0 ; i < M ; i++)
            {
                int u,v;
                scanf("%d%d",&u,&v);
                u--;
                v--;
                slover.G[u][v] = 0;
                slover.G[v][u] = 0;
            }
            int res = slover.MaxClique();
            printf("%d
    ",res);
            for (int i = 1 ; i <= res ; i++)
            {
                printf("%d%c",slover.ret[i] + 1,i == res ? '
    ' : ' ');
            }
        }
        return 0;
    }
    View Code


    POJ 1129 Channel Allocation

    最多26个点的无向图,要求相邻的节点不能染成同一个颜色,问最少需要多少颜色染完所有的顶点

    利用结论:最少需要的颜色的数量=最大团点的数量

    #include <map>
    #include <set>
    #include <list>
    #include <cmath>
    #include <ctime>
    #include <deque>
    #include <stack>
    #include <queue>
    #include <cctype>
    #include <cstdio>
    #include <string>
    #include <vector>
    #include <climits>
    #include <cstdlib>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #define LL unsigned long long
    #define PI 3.1415926535897932626
    typedef long long type;
    using namespace std;
    type gcd(type a, type b) {return b == 0 ? a : gcd(b, a % b);}
    const int MAXN = 110;
    struct Max_Clique
    {
        int G[MAXN][MAXN];
        int N,MAX[MAXN],Alt[MAXN][MAXN],ans;
    
        void init(int n)
        {
            N = n;
        }
        bool dfs(int cur,int tot)
        {
            if (cur == 0)
            {
                if (tot > ans)
                {
                    ans = tot;
                    return true;
                }
                return false;
            }
            for (int i = 0 ; i < cur ; i++)
            {
                if (cur - i + tot <= ans) return false;
                int u = Alt[tot][i];
                if (MAX[u] + tot <= ans) return false;
                int nxt = 0;
                for (int j = i + 1 ; j < cur ; j++)
                    if (G[u][Alt[tot][j]]) Alt[tot + 1][nxt++] = Alt[tot][j];
                if (dfs(nxt,tot + 1)) return true;
            }
            return false;
        }
    
        int MaxClique()
        {
            ans = 0;
            memset(MAX,0,sizeof(MAX));
            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;
        }
    }slover;
    
    
    int main()
    {
        int N;
        while (scanf("%d",&N) != EOF)
        {
            if (N == 0) break;
            slover.init(N);
            char str[5010];
            memset(slover.G,0,sizeof(slover.G));
            for (int i = 0 ; i < N ; i++)
            {
                scanf("%s",str);
                int len = strlen(str);
                for (int j = 2 ; j < len ; j++)
                {
                    int id = str[j] - 'A';
                    slover.G[i][id] = slover.G[id][i] = true;
                }
            }
            int ret = slover.MaxClique();
            if (ret == 1) printf("1 channel needed.
    ");
            else  printf("%d channels needed. 
    ", ret);
        }
        return 0;
    }
    View Code
  • 相关阅读:
    VS2019调试 asp.net core 2.2 出现《ANCM In-Process Handler Load Failure 发布后启动错误处理》处理
    网页上显示数学公式的三种方案
    FileStream实现多线程断点续传(已封装)
    绝对定位不脱离文档流的方法
    百度地图InfoWindow弹窗圆角
    并发:线程池异步执行与创建单独的线程执行
    互斥锁和自旋锁的区别
    事务的特性和隔离级别
    线程不安全与线程安全示例
    多线程过去与现在
  • 原文地址:https://www.cnblogs.com/Commence/p/4945575.html
Copyright © 2011-2022 走看看