zoukankan      html  css  js  c++  java
  • 最大团 HDU-1530

     传送门: 洛谷  Vjudge    (题目略有不同)

    题目描述
      • 给定一个图 tt = (V, E)
      • 求一个点集 S ,使得对于任意 x ≠ y ∈ S ,x 和 y 都有一条边
      • |V | ≤ 50
    输入格式
      第一行两个数,n, m 分别表示图的点数、边数。 接下
      来 m 行,每行两个整数 x, y 表示一条边 x ↔ y 。
    输出格式
      输出最大团的大小以及最大团的数目。
    样例输入
      4 5
      1 2
      2 3
      3 1
      1 4
      2 4
    样例输出
      3 2

    1. 搜索  2BornKerbosch算法 3.取反图求最大独立集 meet in the middle

    1.  DFS 

      就是从每一个点出发找最大团

      从u点出发 枚举和u相连的点 check一下它是不是和现在找到的团一起构成完全图 

      如果是 就继续往下搜 不是 就继续找下一个点

      最重要的是找相连的点的顺序!!!

      这一步处理不好的话 既会找到重复的点 而且循环也是没完没了

      这里的方法是 只要找标号比 u 大的与之相连的点即可

      这样就有了一定的顺序性 而且也不会遗漏 

      因为假如最大的完全图中 有 u 还有比 u 小的点 v 

      即使在搜 u 时搜不到这个图 但是搜此图中标号最小的点时是一定搜得到的

      但是 这仍然不是最优秀的搜索 还有别的剪枝

        f [i] :从第 i , i+1, i+2 ,…,n 点中选出的最大团所含的点数 

        nw为现在选到的点 st为现在已经选出的点数+1 

        ans1 为最大团点数 ans2 为最大团的数量

      所谓"正难则反" 我们从 f [n] 求到 f[1]

      发现 f[i] 最大也只能为 f[i-1]+1

      所以 if ( st + f [nw+1] <ans1) 就直接 return 了 (最优性剪枝)

      However  这样子只能过掉HDU-1530 洛谷还是TLE

     

    小结一下:    

        搜索的顺序可以解决很多问题啊 

        但是不要乱了 可以把问题一一列举出来 

        每想到一个方案的时候仔细想是不是可以解决这些问题

        想清楚 不要轻易否决了

        多想想要求的量之间的关系 有可能可以用于优化

     1 #include<iostream>
     2 #include<cstdio>
     3 #define go(i,a,b) for(register int i=a;i<=b;i++)
     4 #define yes(i,a,b) for(register int i=a;i>=b;i--)
     5 #define fre(x) freopen("x.in","r",stdin) freopen("x.out","w",stdout)
     6 using namespace std;
     7 int read()
     8 {
     9     int x=0,y=1;char c=getchar();
    10     while(c<'0'||c>'9') {if(c=='-') y=-1;c=getchar();}
    11     while(c>='0'&&c<='9') {x=(x<<1)+(x<<3)+c-'0';c=getchar();}
    12     return x*y;
    13 }
    14 int n,m,x,y,ans1,ans2;
    15 int tmp[100],f[100];
    16 bool mp[100][100];
    17 bool ck(int x,int y)
    18 {
    19     go(i,1,y) {if(!mp[x][tmp[i]]) return 0;}
    20     return 1;
    21 }
    22 int dfs(int nw,int st)
    23 {
    24     if(st+f[nw+1]<ans1) return ans1; 
    25     if(st>ans1) {ans1=st;ans2=1;return ans1;}
    26     else if(st==ans1) ans2++;
    27     tmp[st]=nw;
    28     go(i,nw+1,n) {if(ck(i,st)) dfs(i,st+1);}
    29     return ans1;
    30 }
    31 int main()
    32 {
    33     //fre(1);
    34     n=read();m=read();
    35     go(i,1,m) {x=read();y=read();mp[x][y]=mp[y][x]=1;}
    36     yes(i,n,1) {f[i]=dfs(i,1);}
    37     printf("%d %d",ans1,ans2);
    38     return 0;
    39 }
    40 
    41 法1 洛谷 90pts View Code
    法1 洛谷 90pts Code
     1 #include<iostream>
     2 #include<cstdio>
     3 #define go(i,a,b) for(register int i=a;i<=b;i++)
     4 using namespace std;
     5 int read()
     6 {
     7     int x=0,y=1;char c=getchar();
     8     while(c<'0'||c>'9') {if(c=='-') y=-1;c=getchar();}
     9     while(c>='0'&&c<='9') {x=(x<<1)+(x<<3)+c-'0';c=getchar();}
    10     return x*y;
    11 }
    12 int n,m,x,y,ans1,ans2;
    13 int tmp[100];
    14 bool mp[100][100];
    15 bool ck(int x,int y)
    16 {
    17     go(i,1,y) {if(!mp[x][tmp[i]]) return 0;}
    18     return 1;
    19 }
    20 void dfs(int nw,int st)
    21 {
    22     if(st>ans1) {ans1=st;ans2=1;}
    23     else if(st==ans1) ans2++;
    24     tmp[st]=nw;
    25     go(i,nw+1,n) {if(ck(i,st)) dfs(i,st+1);}
    26 }
    27 int main()
    28 {
    29     while(n=read())
    30    {
    31        if(!n) break ;
    32        ans1=ans2=0;
    33        go(i,1,n) go(j,1,n) mp[i][j]=0;
    34        go(i,1,n) go(j,1,n) mp[i][j]=read();
    35        go(i,1,n) dfs(i,1);
    36        printf("%d
    ",ans1); 
    37    }
    38     return 0;
    39 }
    法1 HDU AC Code

     

    2. BornKerbosch算法 

     

      构造两个数组 P R 

      R 中存进入当前搜索的团中的点

      P 中存可能进入R中的点

      初始化 P里为所有元素 R 为空

      依次把 P 里的数丢进 R里

      我们现在把 v 放入 R 中 则要把 P 中不与 v 相连的点全都去掉 然后重复此步骤

            递归实现

      回溯时 R P 三个数组也要回溯成原来的样子

      为了方便 这三个数组可以设两个维度

      第一个维度表示现在所在的层数 第二个维度存元素

      还有一个优化 在同一层中 取了 v 那么就不必要取和 v 相连的点了 

            我的理解是这样的:

        假如 u 与 v 相连 我们取了 v 后不必要取 u 了

         u 所在的最大团有两种情况 : 1. 包括 v 那么取 v 时一定可以找到这个团

                     2. 不包括v 那么团里一定有别的点不与 v 相连

                      那么取那个点是一定可以找到这个团

        综上,没有取 u 的必要

     1 //BornKerbosch算法
     2 #include<bits/stdc++.h>
     3 using namespace std;
     4 #define RI register int
     5 #define LL long long
     6 inline int read()
     7 {
     8     int res=0,f=1;
     9     char ch=getchar();
    10     while(ch!='-'&&(ch>'9'||ch<'0'))
    11         ch=getchar();
    12     if(ch=='-')
    13         f=-1,ch=getchar();
    14     while(ch>='0'&&ch<='9')
    15         res=(res<<1)+(res<<3)+(ch^48),ch=getchar();
    16     return res*f;
    17 }
    18 const int N=100;
    19 int ans,maxn;
    20 int R[N][N],P[N][N],X[N][N];
    21 bool f[55][55];
    22 void dfs(int d,int x,int y)
    23 {
    24     if(!y)
    25     {
    26         if(d-1>maxn)
    27         {
    28             maxn=d-1;
    29             ans=1;
    30         }
    31         else
    32         {
    33             if(d-1==maxn)
    34                 ans++;
    35         }
    36         return;
    37     }
    38     int u=P[d][1];
    39     for(RI i=1;i<=y;++i)
    40     {
    41         int v=P[d][i];
    42         if(f[v][u])continue;
    43         for(RI j=1;j<=x;++j)
    44             R[d+1][j]=R[d][j];
    45         R[d+1][x+1]=v;
    46         int ty=0,tz=0;
    47         for(RI j=1;j<=y;++j)
    48             if(f[v][P[d][j]])
    49                 P[d+1][++ty]=P[d][j];
    50         dfs(d+1,x+1,ty);
    51         P[d][i]=0;
    52     }
    53 }
    54 int main()
    55 {
    56     int n=read(),m=read();
    57     for(RI i=1;i<=m;++i)
    58     {
    59         int x=read(),y=read();
    60         f[x][y]=f[y][x]=1;
    61     }
    62     for(RI i=1;i<=n;++i)
    63         P[1][i]=i;
    64     dfs(1,0,n);
    65     printf("%d %d",maxn,ans);
    66     return 0;
    67 }
    68 //Written By Air_Castle
    法2 洛谷 lyh's code

      then  我发现 根本就不需要 R 数组啊

     1 #include<iostream>
     2 #include<cstdio>
     3 #define go(i,a,b) for(register int i=a;i<=b;i++)
     4 using namespace std;
     5 int read()
     6 {
     7     int x=0,y=1;char c=getchar();
     8     while(c<'0'||c>'9') {if(c=='-') y=-1;c=getchar();}
     9     while(c>='0'&&c<='9') {x=(x<<1)+(x<<3)+c-'0';c=getchar();}
    10     return x*y;
    11 }
    12 int n,m,ans1,ans2,P[100][100];
    13 bool mp[100][100];
    14 void dfs(int st,int y) //st:step x:R's num y:P's num
    15 {
    16     if(!y)
    17     {
    18         if(st-1>ans1) {ans1=st-1;ans2=1;}
    19         else if(st-1==ans1) ans2++;
    20         return ;
    21     }
    22     int u=P[st][1];
    23     go(i,1,y)
    24     {
    25         int v=P[st][i];
    26         if(mp[u][v]) continue ;
    27         int cnt=0;
    28         go(j,1,y)
    29             if(mp[v][P[st][j]]) P[st+1][++cnt]=P[st][j];
    30         dfs(st+1,cnt);
    31         P[st][i]=0;
    32     }
    33 }
    34 int main()
    35 {
    36     n=read();m=read();
    37     go(i,1,m) {int x=read(),y=read();mp[x][y]=mp[y][x]=1;}
    38     go(i,1,n) P[1][i]=i;
    39     dfs(1,n);
    40     printf("%d %d",ans1,ans2);
    41     return 0;
    42 }
    法2 洛谷 dtt's code

       

    3. 我还不会 ! ! ! qwq

    光伴随的阴影
  • 相关阅读:
    Billing Invoice Split Rule
    From ProjectMagazine
    Link to PMP
    测试发现数据库性能问题后的SQL调优
    被jQuery折腾得半死,揭秘为何jQuery为何在IE/Firefox下均无法使用
    解决'将 expression 转换为数据类型 nvarchar 时出现算术溢出错误。'
    几年来ASP.NET官方站点首次改版,意味着MVC时代全面到来?
    Collection was modified; enumeration operation may not execute.的异常处理
    解决Sandcastle Help File Builder报错问题
    如何查看Windows服务所对应的端口?
  • 原文地址:https://www.cnblogs.com/forward777/p/10322653.html
Copyright © 2011-2022 走看看