zoukankan      html  css  js  c++  java
  • 对最大团的理解

    定义: 
        最大团就是给你一个图,让你在这个图里面找到一个最大的子图,这个子图必须是全图,最大的子图就是这个图的最大团。


    算法:
          首先最大团是NP问题,没有什么非常快的方法去解决,现在可以用搜索+剪枝去尽可能的快速处理最大团问题,其中一个很重要的剪枝就是如果当前集合的顶点数+剩下所有的点<当前全局的最优答案,那么直接return,不然搜下去也没意义,我们要枚举每一个团,找到最大的那个,对于当前点,如果满足要求(和当前团所有点都有连边)那么他可以加入团或者放弃,如果满足要求,直接放弃,一直枚举,更新最优就行了。
    接着补充一下,经过做3585的那个二分最大团发现自己写的模板各种超时,超时到蛋疼,最后学了下dp优化的,然后就过了,dp优化的理解是这样的,对于dp优化首先我们要知道如果这样的写法


    枚举第一个点的时候for(int i = n - 1 ;i >= 1 ;i --)
    DFS里面跑的时候for(int i = x + 1 ;i <= n ;i ++)
    这样就导致每次DFS是比上次增加了一个节点,对于当前点的本次搜索索要面临的点都已经被枚举过了,然后当前这个点加入如果是"有效"的,那么他肯定是之前的某一个团+1,如果当前的这个点要走的点+要走的那个点的之前最大团还是没有当前全局答案大,那么就没有必要遍历了,直接就continue就行了。


    //*******************************
    最大团:图G的顶点的子集D,若D中任意两点相邻,且含有的顶点数最大,则D为最大团。
            因此若u,v在最大团中,则u,v必有边相连
            一个有N个顶点的最大团,边数为N*(N-1)/2
    求最大团是NP问题,常用的方法是DP优化+ DFS
     
    与之相关的概念是最大独立集:
    独立集是指图的顶点集的一个子集,该子集的导出子图不含边。
    一个图中包含顶点数目最多的独立集称为最大独立集。
    所以最大独立子集=图的补图的最大团
    //***********************************


    自己写的一个模板(容易超时)


    #include<stdio.h>


    #define N 60


    int map[N][N] ,n;
    int now[N] ,Ans;


    bool ok(int sum ,int to)
    {
       for(int i = 1 ;i <= sum ;i ++)
       if(!map[now[i]][to]) return 0;
       return 1;
    }


    void DFS(int to ,int sum ,int node)
    {
       if(Ans < sum) Ans = sum;
       if(sum + n - node < Ans) return;
       for(int i = to + 1 ;i <= n ;i ++)
       if(ok(sum ,i)) 
       {
          now[sum + 1] = i;
          DFS(i ,sum + 1 ,node + 1);
       }
    }


    int main ()
    {
       int i ,j;
       while(~scanf("%d" ,&n) && n)
       {
          for(i = 1 ;i <= n ;i ++)
          for(j = 1 ;j <= n ;j ++)
          scanf("%d" ,&map[i][j]);
          Ans = 0;
          for(i = 1 ;i <= n ;i ++)
          {
             now[1] = i;
             DFS(i ,1 ,1);
          }
          printf("%d " ,Ans);
       }
       return 0;
    }


    dp优化的(目前比较快的)
    #include<stdio.h>


    #define N 60


    int map[N][N];
    int dp[N] ,now[N];
    int n ,Ans;


    void DFS(int x ,int sum)
    {
       if(sum > Ans) Ans = sum;
       
       int able = 0;
       int tnow[N];
       for(int i = x + 1 ;i <= n ;i ++)
       {
          tnow[i] = now[i];
          if(now[i]) able ++;
       }
       if(able + sum <= Ans) return;
       
       for(int i = x + 1 ;i <= n ;i ++)
       {
          if(!tnow[i]) continue;
          if(dp[i] + sum <= Ans) return;
          for(int j = x + 1 ;j <= n ;j ++)
          now[j] = tnow[j] & map[i][j];
          DFS(i ,sum + 1);
       }
    }


    int Max_Tuan()
    {
       Ans = dp[n] = 1;
       for(int i = n - 1 ;i >= 1 ;i --)
       {
          for(int j = 1 ;j <= n ;j ++)
          now[j] = map[i][j];
          DFS(i ,1);
          dp[i] = Ans;
       }
       return Ans;
    }


    int main ()
    {
       int i ,j;
       while(~scanf("%d" ,&n) && n)
       {
          for(i = 1 ;i <= n ;i ++)
          for(j = 1 ;j <= n ;j ++)
          scanf("%d" ,&map[i][j]);
          printf("%d " ,Max_Tuan());
       }
       return 0;
    }
       
       








          
  • 相关阅读:
    文件操作
    python中的函数递归和迭代问题
    函数的闭包与装饰器
    函数的名称空间和作用域
    python学习之路(四) ---函数
    python __name__问题
    浅谈python中的引用和拷贝问题
    Python中的缩进问题
    粘包现象
    socket编程
  • 原文地址:https://www.cnblogs.com/csnd/p/12062888.html
Copyright © 2011-2022 走看看