问题描叙:
对一个给定的图找出最佳着色,只能用黑色和白色,着色规则是任何相连接的节点不可能同时都是黑色。
分析:这题是典型的求最大独立集,有个定理(这里就不写证明了):图的最大独立集=它的补图的最大团。
所以先构造器补图,然后计算补图的最大团,先按照序号递减的顺序,依次将节点i作为当前的第i各节点,然后将节点i+1到n中与节点i邻接的点置在一个集合里(get)
程序中:
map[][]为图(在输入的时候就变换成了原图的补图)
ans[]为当前的最大团结果序列。
dp[i]表示节点i到n之间最大团个数。
get[i][]表示当前有两个已经进入最大团时,其中最后一个节点k(表示当前最大团里的i个节点序号最后的那个节点)之后与它相连接的节点集合。
M表示最大团的个数(随着DFS的进行,持续更新)
DFS完成整个程序,贴上代码:
1 #include<stdio.h> 2 #include<string.h> 3 #define MAX 110 4 bool map[MAX][MAX]; 5 int n,M,sum,sum1; 6 int ans[MAX],dp[MAX],get[MAX][MAX],node[MAX]; 7 void dfs(int now,int sum) 8 { 9 int i,j,v; 10 if(sum==0){ 11 if(now>=M){ 12 M=now; 13 for(i=1;i<=M;i++) 14 ans[i]=node[i]; 15 } 16 return ; 17 } 18 for(i=1;i<=sum;i++){ 19 v=get[now][i],sum1=0; 20 if(now+dp[v]<M) return ; 21 for(j=i+1;j<=sum;j++) 22 if(map[v][ get[now][j] ]) get[now+1][++sum1]=get[now][j]; 23 node[now+1]=v; 24 dfs(now+1,sum1); 25 } 26 } 27 void slove() 28 { 29 memset(dp,0,sizeof(dp)); 30 memset(get,0,sizeof(get)); 31 int i,j; 32 M=0; 33 for(i=n;i>=1;i--){ 34 sum=0,node[1]=i; 35 for(j=i+1;j<=n;j++) 36 if(map[i][j]) get[1][++sum]=j; 37 dfs(1,sum); 38 dp[i]=M; 39 } 40 printf("%d ",M); 41 for(i=1;i<=M;i++) 42 printf("%d ",ans[i]); 43 printf(" "); 44 } 45 void init() 46 { 47 int k,i,x,y; 48 memset(map,true,sizeof(map)); 49 scanf("%d%d",&n,&k); 50 for(i=1;i<=k;i++){ 51 scanf("%d%d",&x,&y); 52 map[x][y]=map[y][x]=false; 53 } 54 } 55 int main() 56 { 57 int N; 58 scanf("%d",&N); 59 while(N--){ 60 init(); 61 slove(); 62 } 63 return 0; 64 }