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

来源:互联网 发布:黑马程序员学费多少 编辑:程序博客网 时间:2024/06/05 18:36

思路

独立集:点集中的所有点两两无边。
一个结论:一个无向图的最大独立集(点数最多)等于其补图的最大团(两两有边)
暴力枚举所有的子集,并对子集进行染色
预处理时去掉存在非独立集的子集,然后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 statusint 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;}
0 0
原创粉丝点击