最大团问题

讲解就在这里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
原文地址:https://www.cnblogs.com/Commence/p/4945575.html