最大团问题
PS:看了百科你会晕,你会感觉这东西好难。 百科传送阵:http://baike.baidu.com/view/7343867.htm?fr=aladdin
最大团:一幅无向图的顶点最多的(最大)完全子图。完全图就是每个点的度数都等于n-1的无向图。 百科传送阵: http://baike.baidu.com/view/2780567.htm?fr=aladdin
有以下结论:
1、最大团点的数量=补图中最大独立集点的数量,二分图中,最大独立集点顶点个数= 顶点数 - 最大匹配数
2、图的染色问题中,最少需要的颜色的数量=最大团点的数量
可以看出来,我们可以通过最大匹配来解最大团问题。有一个问题需要解决,这种方式可不可以记录最大团中点的编号,因为有些题需要输出点。我们知道,在无向图中,最大匹配输等于求出的匹配数的二分之一。在记录与X集合匹配的点的时候,如果最大匹配的值是1,记录数组中就会有两个值不是-1(-1是初始化的)。那么到底哪一点是最大团里的呢?不能确定。所以通过最大匹配来求不适合。比较尴尬的是,我用Hopcroft-Karp算法来求补图中的最大匹配的方式来做的时候,hdu1530一直AC不了。所以这方法还是别用来,至少我不用了。
网上流行的模版都是通过深搜来完成。传送门:http://www.cnblogs.com/zhj5chengfeng/archive/2013/07/29/3224092.html
上面的博客讲的很好。就借用了。
我的模版来自:http://blog.csdn.net/leolin_/article/details/7251962
其实这模版上上面一个链接里的模版是一样。上面那个通过结构体封装了。下面的是C语言风格。
模版:
tuan[]记录最大团的顶点,ans就是所求的最大团的顶点数,num[i]表示由结点i到结点n构成的最大团的结点数,can[i]表示在已经确定了经选定的i个点必须在最大团内的前提下还有可能被加进最大团的结点集合,g[][]邻接矩阵(从1开始)。
1 const int N=102; 2 int ans; 3 int x[N],tuan[N]; 4 int can[N][N]; 5 int num[N]; 6 bool g[N][N]; 7 int n,m; 8 bool dfs(int tot,int cnt){ 9 int i,j,k; 10 if(tot == 0){ 11 if(cnt > ans){ 12 ans = cnt; 13 for(i=0;i<ans;i++){ 14 tuan[i] = x[i]; 15 } 16 return true; 17 } 18 return false; 19 } 20 for(i=0;i<tot;i++){ 21 if(cnt + (tot-i) <= ans)return false; 22 if(cnt + num[can[cnt][i]] <= ans)return false; 23 k = 0; 24 x[cnt] = can[cnt][i]; 25 for(j=i+1;j<tot;j++){ 26 if(g[can[cnt][i]][can[cnt][j]]){ 27 can[cnt+1][k++] = can[cnt][j]; 28 } 29 } 30 if(dfs(k,cnt+1))return false; 31 } 32 return false; 33 } 34 void mc(){ 35 int i,j,k; 36 ans = 1; 37 for(i=n;i>=1;i--){ 38 k = 0; 39 x[0] = i; 40 for(j=i+1;j<=n;j++){ 41 if(g[i][j]){ 42 can[1][k++] = j; 43 } 44 } 45 dfs(k,1); 46 num[i] = ans; 47 } 48 } 49 void init(){ memset(g,0,sizeof(g)); }
hdu 1530 Maximum Clique
核对模版的题目
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 const int N=102; 7 int ans; 8 int x[N],tuan[N]; 9 int can[N][N]; 10 int num[N]; 11 bool g[N][N]; 12 int n,m; 13 bool dfs(int tot,int cnt){ 14 int i,j,k; 15 if(tot == 0){ 16 if(cnt > ans){ 17 ans = cnt; 18 for(i=0;i<ans;i++){ 19 tuan[i] = x[i]; 20 } 21 return true; 22 } 23 return false; 24 } 25 for(i=0;i<tot;i++){ 26 if(cnt + (tot-i) <= ans)return false; 27 if(cnt + num[can[cnt][i]] <= ans)return false; 28 k = 0; 29 x[cnt] = can[cnt][i]; 30 for(j=i+1;j<tot;j++){ 31 if(g[can[cnt][i]][can[cnt][j]]){ 32 can[cnt+1][k++] = can[cnt][j]; 33 } 34 } 35 if(dfs(k,cnt+1))return false; 36 } 37 return false; 38 } 39 void mc(){ 40 int i,j,k; 41 ans = 1; 42 for(i=n;i>=1;i--){ 43 k = 0; 44 x[0] = i; 45 for(j=i+1;j<=n;j++){ 46 if(g[i][j]){ 47 can[1][k++] = j; 48 } 49 } 50 dfs(k,1); 51 num[i] = ans; 52 } 53 } 54 void init(){ memset(g,0,sizeof(g)); } 55 56 int main() 57 { 58 //freopen("test.txt","r",stdin); 59 int i,j; 60 while(scanf("%d",&n)!=EOF&&n) 61 { 62 init(); 63 for(i=1;i<=n;i++) 64 for(j=1;j<=n;j++) 65 scanf("%d",&g[i][j]); 66 mc(); 67 printf("%d\n",ans); 68 } 69 return 0; 70 }
poj1419 Graph Coloring
核对模版,输出最大团中的点
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 const int N=102; 7 int ans; 8 int x[N],tuan[N]; 9 int can[N][N]; 10 int num[N]; 11 bool g[N][N],p[N][N]; 12 int n,m; 13 bool dfs(int tot,int cnt){ 14 int i,j,k; 15 if(tot == 0){ 16 if(cnt > ans){ 17 ans = cnt; 18 for(i=0;i<ans;i++){ 19 tuan[i] = x[i]; 20 } 21 return true; 22 } 23 return false; 24 } 25 for(i=0;i<tot;i++){ 26 if(cnt + (tot-i) <= ans)return false; 27 if(cnt + num[can[cnt][i]] <= ans)return false; 28 k = 0; 29 x[cnt] = can[cnt][i]; 30 for(j=i+1;j<tot;j++){ 31 if(g[can[cnt][i]][can[cnt][j]]){ 32 can[cnt+1][k++] = can[cnt][j]; 33 } 34 } 35 if(dfs(k,cnt+1))return false; 36 } 37 return false; 38 } 39 void mc(){ 40 int i,j,k; 41 ans = 1; 42 for(i=n;i>=1;i--){ 43 k = 0; 44 x[0] = i; 45 for(j=i+1;j<=n;j++){ 46 if(g[i][j]){ 47 can[1][k++] = j; 48 } 49 } 50 dfs(k,1); 51 num[i] = ans; 52 } 53 } 54 void init(){ memset(g,0,sizeof(g));memset(p,0,sizeof(p)); } 55 56 int main() 57 { 58 //freopen("test.txt","r",stdin); 59 int i,j,cas; 60 scanf("%d",&cas); 61 while(cas--) 62 { 63 scanf("%d%d",&n,&m); 64 init(); 65 while(m--) 66 { 67 scanf("%d%d",&i,&j); 68 p[i][j]=1; 69 } 70 for(i=1;i<=n;i++) 71 for(j=1;j<=n;j++) 72 g[i][j]=p[i][j] ^1; 73 mc(); 74 printf("%d\n",ans); 75 for(i=0;i<ans-1;i++) 76 printf("%d ",tuan[i]); 77 printf("%d\n",tuan[i]); 78 } 79 return 0; 80 }
hdu1045/zoj1002 Fire Net
PS:记得当初,做了ZOJ第一题向按顺序试试。结果悲剧了。
求的是最大独立集(方法挺多的)
这是用最大团来最的代码:
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 const int N=102; 7 int ans; 8 int x[N],tuan[N]; 9 int can[N][N]; 10 int num[N]; 11 bool g[N][N]; 12 int n,m; 13 bool dfs(int tot,int cnt){ 14 int i,j,k; 15 if(tot == 0){ 16 if(cnt > ans){ 17 ans = cnt; 18 for(i=0;i<ans;i++){ 19 tuan[i] = x[i]; 20 } 21 return true; 22 } 23 return false; 24 } 25 for(i=0;i<tot;i++){ 26 if(cnt + (tot-i) <= ans)return false; 27 if(cnt + num[can[cnt][i]] <= ans)return false; 28 k = 0; 29 x[cnt] = can[cnt][i]; 30 for(j=i+1;j<tot;j++){ 31 if(g[can[cnt][i]][can[cnt][j]]){ 32 can[cnt+1][k++] = can[cnt][j]; 33 } 34 } 35 if(dfs(k,cnt+1))return false; 36 } 37 return false; 38 } 39 void mc(){ 40 int i,j,k; 41 ans = 1; 42 for(i=n*n;i>=1;i--){ 43 k = 0; 44 x[0] = i; 45 for(j=i+1;j<=n*n;j++){ 46 if(g[i][j]){ 47 can[1][k++] = j; 48 } 49 } 50 dfs(k,1); 51 num[i] = ans; 52 } 53 } 54 void init(){ memset(g,true,sizeof(g));} 55 bool isin(int x, int y) 56 { 57 return x>=0&&x<n&&y>=0&&y<n; 58 } 59 int dx[4]={0,0,-1,1}; 60 int dy[4]={1,-1,0,0}; 61 char str[8][8]; 62 int main() 63 { 64 //freopen("test.txt","r",stdin); 65 int i,j,k,a,b,x,y,X; 66 while(scanf("%d",&n)!=EOF&&n) 67 { 68 init(); 69 getchar(); 70 for(i=0;i<n;i++) gets(str[i]); 71 X=0; 72 for(i=0;i<n;i++) 73 { 74 for(j=0;j<n;j++) 75 { 76 a=i*n + j+1; 77 if(str[i][j]=='X'){ 78 X++;continue; 79 } 80 for(k=0;k<4;k++) 81 { 82 x=i+dx[k]; y=j+dy[k]; 83 while(isin(x,y)&&str[x][y]=='.') 84 { 85 b=x*n+y+1; 86 g[a][b]=0; 87 x+=dx[k]; y+=dy[k]; 88 } 89 } 90 } 91 } 92 mc(); 93 printf("%d\n",ans-X); 94 } 95 return 0; 96 }
poj1129 Channel Allocation
染色问题中最少需要的颜色问题等价于最大团问题
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 const int N=102; 7 int ans; 8 int x[N],tuan[N]; 9 int can[N][N]; 10 int num[N]; 11 bool g[N][N]; 12 int n,m; 13 bool dfs(int tot,int cnt){ 14 int i,j,k; 15 if(tot == 0){ 16 if(cnt > ans){ 17 ans = cnt; 18 for(i=0;i<ans;i++){ 19 tuan[i] = x[i]; 20 } 21 return true; 22 } 23 return false; 24 } 25 for(i=0;i<tot;i++){ 26 if(cnt + (tot-i) <= ans)return false; 27 if(cnt + num[can[cnt][i]] <= ans)return false; 28 k = 0; 29 x[cnt] = can[cnt][i]; 30 for(j=i+1;j<tot;j++){ 31 if(g[can[cnt][i]][can[cnt][j]]){ 32 can[cnt+1][k++] = can[cnt][j]; 33 } 34 } 35 if(dfs(k,cnt+1))return false; 36 } 37 return false; 38 } 39 void mc(){ 40 int i,j,k; 41 ans = 1; 42 for(i=n;i>=1;i--){ 43 k = 0; 44 x[0] = i; 45 for(j=i+1;j<=n;j++){ 46 if(g[i][j]){ 47 can[1][k++] = j; 48 } 49 } 50 dfs(k,1); 51 num[i] = ans; 52 } 53 } 54 void init(){ memset(g,0,sizeof(g)); } 55 int main() 56 { 57 //freopen("test.txt","r",stdin); 58 int i,j,k,cas; 59 char ch; 60 while(scanf("%d",&n)!=EOF&&n) 61 { 62 init(); 63 getchar(); 64 for(i=1;i<=n;i++) 65 { 66 getchar();getchar(); 67 while((ch=getchar())!='\n') 68 { 69 j=ch-64; 70 g[i][j]=1; 71 } 72 } 73 mc(); 74 printf("%d ",ans); 75 if(ans==1) printf("channel needed.\n"); 76 else printf("channels needed.\n"); 77 } 78 return 0; 79 }