题目大意:
一个无向图中,使用黑白两种颜色对顶点着色,要求相邻顶点不能同时为黑色,求最大能染黑色顶点数量以及对应顶点。
解题思路:
相邻顶点间有边相连,模型转换成求 无向图 最大独立集。因为是NP问题,目前没有有效算法。
又 最大团顶点数量 = 补图的最大独立集
所以我们可以用 优化的 Bron-Kerbosch算求其补图的最大团,然后得出当前图的最大独立集
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<cstdio> #include<cstring> #define N 1010 bool flag[N], a[N][N]; int ans, cnt[N], group[N], n, m, vis[N]; bool dfs( int u, int pos ){ int i, j; for( i = u+1; i <= n; i++){ if( cnt[i]+pos <= ans ) return 0; if( a[u][i] ){ // 与目前团中元素比较,取 Non-N(i) for( j = 0; j < pos; j++ ) if( !a[i][ vis[j] ] ) break; if( j == pos ){ // 若为空,则皆与 i 相邻,则此时将i加入到 最大团中 vis[pos] = i; if( dfs( i, pos+1 ) ) return 1; } } } if( pos > ans ){ for( i = 0; i < pos; i++ ) group[i] = vis[i]; // 最大团 元素 ans = pos; return 1; } return 0; } void maxclique() { ans=-1; for(int i=n;i>0;i--) { vis[0]=i; dfs(i,1); cnt[i]=ans; } } int main(){ int T; scanf("%d",&T); while( T-- ){ scanf("%d%d",&n,&m ); int x, y; memset( a, 0, sizeof(a)); for(int i = 0; i < m; i++){ scanf("%d%d",&x,&y); a[x][y] = a[y][x] = 1; } for(int i = 1; i <= n; i++) for(int j = 1; j <= n; j++) if( i == j ) a[i][j] = 0; else a[i][j] ^= 1; maxclique(); if( ans < 0 ) ans = 0; printf("%d\n", ans ); for(int i = 0; i < ans; i++) printf( i == 0 ? "%d" : " %d", group[i] ); if( ans > 0 ) puts(""); } }