• 对最大团的理解


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


    算法:
          首先最大团是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;
    }
       
       








          
  • 相关阅读:
    Node 12 值得关注的新特性
    vue实现PC端调用摄像头拍照人脸录入、移动端调用手机前置摄像头人脸录入、及图片旋转矫正、压缩上传base64格式/文件格式
    解决Vuex刷新页面数据丢失问题 ---- vuex-persistedstate持久化数据
    博客搬迁到 gitHub + hexo 去了, 博客园以后比较少更新
    Jenkins结合shell脚本实现(gitLab/gitHub)前端项目自动打包部署服务器
    GET 和 POST 的区别 以及为什么 GET请求 比 POST请求 更快
    Git常用命令及使用,GitLab/GitHub初探,Git/Svn区别
    pc端结合canvas实现简单签名功能
    N的阶乘末尾0的个数和其二进制表示中最后位1的位置
    实现一个动态存储分配
  • 原文地址:https://www.cnblogs.com/csnd/p/12062887.html
Copyright © 2020-2023  润新知