最大团问题

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)); }
View Code

 

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 }
View Code

 

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 }
View Code

 

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 }
View Code

 

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 }
View Code

 

转载于:https://www.cnblogs.com/Potato-lover/p/3993984.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值