无向图的最大团与最大独立集

无向图的最大团与最大独立集

     今天和zxr一起做了pku1419-最大独立集,以及zju1492-最大团,zju1002-最大团的应用。做如下总结:

定义:

1. 无向图的最大独立数: 从V个顶点中选出k个顶,使得这k个顶互不相邻。 那么最大的k就是这个图的最大独立数.

2. 无向图的最大团:   Given a graph G(V, E), a clique is a sub-graph g(v, e), so that for all vertex pairs v1, v2 in v, there exists an edge (v1, v2) in e. Maximum clique is the clique that has maximum number of vertex. (就是从V个顶点选出k个顶,使得这k个顶构成一个完全图,即该子图任意两个顶都有直接的边)

两者的关系:  

1. 原来在图论课上,就学了图论中这些有用的数字: 最小覆盖数,最大独立数,最大匹配数,最大团的数等等。 由上面两者的定义可知:

                                  最大团的个数 = 补图的最大独立数

PS: 原来学二分匹配时就整理过这些数字,他们之间关系是很多。如: 最小覆盖数+最大独立数 = 顶点数。 虽然求出他们都是np问题。但对于特殊的图还是有好的算法的,如:

在二分图中,最小覆盖数 等于 最大匹配数, 而最大独立数又等于 顶点数减去最小覆盖数,所以可以利用匈牙利求出最大独立数等等。所以pku1419其实也可以转化成最大团,取图G的补图,然后调用最大团模板(恩,用这种方法AC的更快)

2. zxr今天也说了一下无向图中的最大团 与 有向图中的强连同分量的 对比, 赞~

实现的算法:

        对于这两个NP问题,自己都是用dfs+剪枝实现的。特别是对于最大团的实现,还用到了DP的思想(下面会提到最大团的实现算法). 呵呵,不错的一句话:

       无向图的最大团和最大独立集问题都可以看作是图G的顶点集V的子集选取问题, 可以用回溯法在O(n*(2^n))时间内解决。

pku1419-Graph Coloring

题目大意:

zju1002 - Fire Net

题目大意:


zju1492-Maximum clique

题目大意: 输入一个无向图G,输出它的最大团个数.

分析:          首先很赞今天学习到的方法,算起来用了4个剪枝。

1. 剪枝1:常用的指定顺序, 即枚举第i个顶后, 以后再枚举时枝考虑下标比大它的, 避免重复。

2. 剪枝2:自己开始从前往后的枚举顶点, TLE两次. 后来从后往前枚举顶点,发现可以利用顶点之间的承袭性.我用num[i] 记录的可选顶点集合为 V[i, i+1, ... , n] 中的最大团数目, 目标是求num[1].

     分析易知, num[i] = num[i+1] 或者 num[i]+1   (num[1...n] 具有非降的单调性,从后往前求)

     由这个式子以及num[]信息的记录,使得我们可以增加两处剪枝:

3.上/下剪枝:假设当前枚举的是顶点x, 它的第一个邻接顶是i (标号一定比x大,即num[i]已经求出) 我们可以知道, 若 1 + num[i] <= best, 那么是没没要往下枚举这个顶点x了,因为包含它的团是不可能超过我们目前的最优值的。

4. 立即返回剪枝: 由于num[i]最大可能为num[i+1]+1, 所以在枚举顶点i时,只要一更新best,可知此时的num[i]就为num[i+1]+1了,不需要再去尝试找其他的方案了,所以应立即返回.

// 刚整理的最大团模板, 所需要提供的就是: 顶点个数n, 以及无向图的邻接矩阵g.
int best;
int num[maxn];
//int x[maxn];   // 取决于是否需要最优解.若需要,还要增加一个path[maxn]数组
int MaximumClique()
{
        int i, j, k;
        int adj[maxn];

         if (n<=0) return 0;

        best = 0;
        for (i=n-1; i>=0; i--)
        {
             //x[0] = i; 路径信息1
             for (k=0,j=i+1; j<n; j++) if ( g[i][j] ) adj[k++] = j;
             dfs(adj, k, 1);
              num[i] = best;
         }

         return best;
}

bool dfs(int *adj, int total, int cnt)
{
       int i, j, k;
       int t[maxn];

       if (total==0)
      { 
                if (best < cnt)
                { 
                      //for (i=0; i<cnt; i++) path[i] = x[i]; //路径信息2
                       best = cnt;
                        return true;
                }
                return false;
       }


       for (i=0; i<total; i++)
       { 
              if (cnt+(total-i) <= best) return false;
              if (cnt+num[adj[i]]<=best) return false;

                //x[cnt]=adj[i]; //路径信息3
                for (k=0,j=i+1; j<total; j++) if (g[adj[i]][adj[j]]) t[k++] = adj[j];

               if ( dfs(t, k, cnt+1) ) return true;
       }

      return false;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值