最大团&最大独立集

给定无向图G=(V,E),其中V是非空集合,称为顶点集;EV中元素构成的无序二元组的集合,称为边集,无向图中的边均是顶点的无序对,无序对常用圆括号“( )”表示。如果U  V,且对任意两个顶点uvU有(u,v)∈E,则称UG的完全子图。G的完全子图UG的团。G的最大团是指G的最大完全子图

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

结论:原图的最大独立集等于补图的最大团(补图:图G的补图,通俗的来讲就是完全图Kn去除G的边集后得到的图Kn-G)

团的大小:点的权值和大小,并不是点的个数.

POJ - 1419

给定一个图,选择若干点涂成黑色,黑色的点之间不能有边相连,求最多涂几个黑点

解析:

即求最大独立集,即补图的最大团

二部图的最大独立集==顶点数-匹配数,普通图的最大独立集==补图的最大团

ac:

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <string>
#include <map>
#include <queue>
#include <vector>
#define ll long long
#define MAXN 105
using namespace std;
int w[MAXN][MAXN];
int use[MAXN]; //进入团的标号
int bestx[MAXN];
int cn,bestn,p,e;

void dfs(int x)
{
    bool flag;
    if(x>p) {
        bestn=cn; //cn的值是递增的
        for( int i=1;i<=p; i++) //赋值给另外一个数组,
            bestx[i]=use[i];
        return ;
    }
    flag=true;
    for( int i=1; i<x; i++)
        if(use[i]&&!w[i][x]) {
            flag=false;
            break;
        }
    if(flag) {
        cn++;
        use[x]=true;
        dfs(x+1);
        cn--;
        use[x]=false;//回溯
    }
    if(cn+p-x>bestn) { //剪枝
        dfs(x+1);
    }
}

int main()
{
    int num,u,v;
    scanf("%d",&num);
    while(num--)
    {
        memset(w,1,sizeof(w));
        memset(use,0,sizeof(use));
        memset(bestx,0,sizeof(bestx));

        scanf("%d%d",&p,&e);
        for(int i=0; i<e; i++)
        {
            scanf("%d%d",&u,&v);
            w[u][v]=0;
            w[v][u]=0;
        }
        cn=bestn=0;
        dfs(1);
        printf("%d\n",bestn);//数目
        for (int i=1; i<=p; i++)
        {
            if(bestx[i])
                printf("%d ",i);
        }
        printf("\n");
    }
    return 0;
}
权值第K小的完全子图:

不懂,先存着

#include<bits/stdc++.h>
using namespace std;
int w[105];
bitset<105>Map[105];
char M[105][105];

struct ss
{
    bitset<105>state;
    long long w;

    bool operator < (const ss & s)const
    {
        return w>s.w;
    }
};

priority_queue<ss>q;
int n,k;
long long spfa(ss now)
{
    q.push(now);

    while(!q.empty())
    {
        now=q.top();
        q.pop();
        k--;

        if(!k)
            return now.w;

        int pos=0;
        for(int i=0;i<n;i++)
            if(now.state[i])
                pos=i+1;

        for(int i=pos; i<n; i++)
        {
            if(now.state[i]==0)
            {
                if((now.state&Map[i])==now.state)//O(1)拓展新状态
                {
                    now.state[i]=1;
                    now.w+=w[i];
                    q.push(now);
                    now.state[i]=0;
                    now.w-=w[i];
                }
            }
        }
    }
    return -1;
}

int main()
{
    scanf("%d %d",&n,&k);
    for(int i=0; i<n; i++)
        scanf("%d",&w[i]);
    for(int i=0; i<n; i++)
        scanf("%s",M[i]);

    for(int i=0; i<n; i++)
        for(int j=0; j<n; j++)
            if(M[i][j]=='1')Map[i].set(j);

    ss now;
    now.state.reset();
    now.w=0;

    printf("%lld\n",spfa(now));
    return 0;
}

HDU - 1530

最大团+dp优化:

#include<stdio.h>
#define MAXN 65

int mp[MAXN][MAXN];
int dp[MAXN],now[MAXN];
int n,Ans;

void DFS(int x ,int sum)
{
    if(sum > Ans)
        Ans = sum;
    int able = 0;
    int tnow[MAXN];
    for(int i = x + 1 ;i <= n ;i ++)
    {
        tnow[i] = now[i];
        if(now[i]) able ++;
    }
    if(able + sum <= Ans)
        return;
    for(int i = x + 1 ;i <= n ;i ++)
    {
        if(!tnow[i]) continue;
        if(dp[i] + sum <= Ans) continue;
        for(int j = x + 1 ;j <= n ;j ++)
        now[j] = tnow[j] & mp[i][j];
        DFS(i ,sum + 1);
    }
}

int Max_Tuan()
{
    Ans = dp[n] = 1;
    for(int i = n - 1 ;i >= 1 ;i --)
    {
        for(int j = 1 ;j <= n ;j ++)
        now[j] = mp[i][j];
        DFS(i ,1);
        dp[i] = Ans;
    }
    return Ans;
}

int main ()
{
    int i ,j;
    while(~scanf("%d",&n)&&n)
    {
        for(i=1;i<=n;i++)
        {
            for(j=1;j<=n;j++)
            {
                scanf("%d",&mp[i][j]);
            }
        }
        printf("%d\n",Max_Tuan());
    }
    return 0;
}

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值