(HDU 5823)2016 Multi-University Training Contest 8 color II (m染色问题、最大独立集、DP)

4 篇文章 0 订阅

思路

独立集:点集中的所有点两两无边。
一个结论:一个无向图的最大独立集(点数最多)等于其补图的最大团(两两有边)
暴力枚举所有的子集,并对子集进行染色
预处理时去掉存在非独立集的子集,然后dp枚举子集,染色即对独立集染色(这样能保证两点相连时颜色不同),最后取一个状态对应的独立集个数的最小值
复杂度 O(N3) ,可能讲的不太清楚,还是看代码吧。。

原来这样可以求i的所有子集呀,一直没想到:

for(int sub=i;sub!=0;sub=(sub-1)&i)

代码

#include <bits/stdc++.h>
#define mem(a,b) memset(a,b,sizeof(a))
#define rep(i,a,b) for(int i=a;i<b;i++)
#define debug(a) printf("a =: %d\n",a);
const int INF=0x3f3f3f3f;
const int maxn=1e3+50;
const int Mod=1e9+7;
const double PI=acos(-1);
typedef long long ll;
typedef unsigned int ui;
using namespace std;

bool mp[20][20];
ui pow233[1<<18],dp[1<<18];
bool ilg[1<<18];  //illegal status

int main() {
    #ifndef ONLINE_JUDGE
        freopen("1003.in","r",stdin);
    #endif
    pow233[0]=1;
    for(int i=1;i<(1<<18);i++){
        pow233[i]=pow233[i-1]*233;
    }
    int n;
    int T; scanf("%d",&T);
    char str[22];
    for(int cs=1;cs<=T;cs++){
        scanf("%d",&n);
        for(int i=0;i<n;i++){
            scanf("%s",str);
            for(int j=0,t;j<n;j++){
                mp[i][j]=str[j]-'0';
            }
        }

        mem(ilg,0);
        //求出独立集(所有点两两无边)
        for(int i=1;i<(1<<n);i++){
            for(int j=0;j<n;j++){
                if (((i>>j) &1)){
                    for(int k=0;k<n;k++){
                        if (((i>>k)&1) && mp[j][k]){
                            ilg[i]=true;
                            break;
                        }
                    }
                }
                if (ilg[i]) break;
            }
        }
        mem(dp,0xff);
        dp[0]=0; //dp[i]表示状态i的最少独立集的个数
        //相当于对独立集染色
        for(int i=1;i<(1<<n);i++){
            for(int sub=i;sub!=0;sub=(sub-1)&i){    //求i的所有子集
                if (!ilg[sub]){
                    dp[i]=min(dp[i],dp[i^sub]+1);
                }
            }
        }
        ui ans=0;
        for(int i=1;i<(1<<n);i++){
            ans=(ans+dp[i]*pow233[i]);
        }
        printf("%u\n",ans);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值