您的位置:首页 > 大数据 > 人工智能

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

2016-08-12 22:09 459 查看

思路

独立集:点集中的所有点两两无边。

一个结论:一个无向图的最大独立集(点数最多)等于其补图的最大团(两两有边)

暴力枚举所有的子集,并对子集进行染色

预处理时去掉存在非独立集的子集,然后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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐