传送门: 洛谷  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

小结一下:    

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

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

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

    想清楚 不要轻易否决了

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

 #include<iostream>
#include<cstdio>
#define go(i,a,b) for(register int i=a;i<=b;i++)
#define yes(i,a,b) for(register int i=a;i>=b;i--)
#define fre(x) freopen("x.in","r",stdin) freopen("x.out","w",stdout)
using namespace std;
int read()
{
int x=,y=;char c=getchar();
while(c<''||c>'') {if(c=='-') y=-;c=getchar();}
while(c>=''&&c<='') {x=(x<<)+(x<<)+c-'';c=getchar();}
return x*y;
}
int n,m,x,y,ans1,ans2;
int tmp[],f[];
bool mp[][];
bool ck(int x,int y)
{
go(i,,y) {if(!mp[x][tmp[i]]) return ;}
return ;
}
int dfs(int nw,int st)
{
if(st+f[nw+]<ans1) return ans1;
if(st>ans1) {ans1=st;ans2=;return ans1;}
else if(st==ans1) ans2++;
tmp[st]=nw;
go(i,nw+,n) {if(ck(i,st)) dfs(i,st+);}
return ans1;
}
int main()
{
//fre(1);
n=read();m=read();
go(i,,m) {x=read();y=read();mp[x][y]=mp[y][x]=;}
yes(i,n,) {f[i]=dfs(i,);}
printf("%d %d",ans1,ans2);
return ;
} 法1 洛谷 90pts

法1 洛谷 90pts Code

 #include<iostream>
#include<cstdio>
#define go(i,a,b) for(register int i=a;i<=b;i++)
using namespace std;
int read()
{
int x=,y=;char c=getchar();
while(c<''||c>'') {if(c=='-') y=-;c=getchar();}
while(c>=''&&c<='') {x=(x<<)+(x<<)+c-'';c=getchar();}
return x*y;
}
int n,m,x,y,ans1,ans2;
int tmp[];
bool mp[][];
bool ck(int x,int y)
{
go(i,,y) {if(!mp[x][tmp[i]]) return ;}
return ;
}
void dfs(int nw,int st)
{
if(st>ans1) {ans1=st;ans2=;}
else if(st==ans1) ans2++;
tmp[st]=nw;
go(i,nw+,n) {if(ck(i,st)) dfs(i,st+);}
}
int main()
{
while(n=read())
{
if(!n) break ;
ans1=ans2=;
go(i,,n) go(j,,n) mp[i][j]=;
go(i,,n) go(j,,n) mp[i][j]=read();
go(i,,n) dfs(i,);
printf("%d\n",ans1);
}
return ;
}

法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 的必要

 //BornKerbosch算法
#include<bits/stdc++.h>
using namespace std;
#define RI register int
#define LL long long
inline int read()
{
int res=,f=;
char ch=getchar();
while(ch!='-'&&(ch>''||ch<''))
ch=getchar();
if(ch=='-')
f=-,ch=getchar();
while(ch>=''&&ch<='')
res=(res<<)+(res<<)+(ch^),ch=getchar();
return res*f;
}
const int N=;
int ans,maxn;
int R[N][N],P[N][N],X[N][N];
bool f[][];
void dfs(int d,int x,int y)
{
if(!y)
{
if(d->maxn)
{
maxn=d-;
ans=;
}
else
{
if(d-==maxn)
ans++;
}
return;
}
int u=P[d][];
for(RI i=;i<=y;++i)
{
int v=P[d][i];
if(f[v][u])continue;
for(RI j=;j<=x;++j)
R[d+][j]=R[d][j];
R[d+][x+]=v;
int ty=,tz=;
for(RI j=;j<=y;++j)
if(f[v][P[d][j]])
P[d+][++ty]=P[d][j];
dfs(d+,x+,ty);
P[d][i]=;
}
}
int main()
{
int n=read(),m=read();
for(RI i=;i<=m;++i)
{
int x=read(),y=read();
f[x][y]=f[y][x]=;
}
for(RI i=;i<=n;++i)
P[][i]=i;
dfs(,,n);
printf("%d %d",maxn,ans);
return ;
}
//Written By Air_Castle

法2 洛谷 lyh's code

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

 #include<iostream>
#include<cstdio>
#define go(i,a,b) for(register int i=a;i<=b;i++)
using namespace std;
int read()
{
int x=,y=;char c=getchar();
while(c<''||c>'') {if(c=='-') y=-;c=getchar();}
while(c>=''&&c<='') {x=(x<<)+(x<<)+c-'';c=getchar();}
return x*y;
}
int n,m,ans1,ans2,P[][];
bool mp[][];
void dfs(int st,int y) //st:step x:R's num y:P's num
{
if(!y)
{
if(st->ans1) {ans1=st-;ans2=;}
else if(st-==ans1) ans2++;
return ;
}
int u=P[st][];
go(i,,y)
{
int v=P[st][i];
if(mp[u][v]) continue ;
int cnt=;
go(j,,y)
if(mp[v][P[st][j]]) P[st+][++cnt]=P[st][j];
dfs(st+,cnt);
P[st][i]=;
}
}
int main()
{
n=read();m=read();
go(i,,m) {int x=read(),y=read();mp[x][y]=mp[y][x]=;}
go(i,,n) P[][i]=i;
dfs(,n);
printf("%d %d",ans1,ans2);
return ;
}

法2 洛谷 dtt's code

  

3. 我还不会 ! ! ! qwq

最大团 HDU-1530的更多相关文章

  1. hdu 1530 最大团模板

    说明摘自:pushing my way 的博文 最大团 通过该博主的代码,总算理解了最大团问题,但是他实现时的代码效率却不算太高.因此在最后献上我的模板.加了IO优化目前的排名是: 6 yejinru ...

  2. hdu 1530 Maximum Clique

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1530 题目分类:最大团问题 DP + DFS 代码: #include<bits/stdc++. ...

  3. hdu 1530 Maximum Clique (最大包)

    Maximum CliqueTime Limit: 20000/10000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)T ...

  4. hdu 3585 二分+最大团

    题目:给出平面上n个点,现在找m个点,并且使得这m个点最近的两个最远. 分析:显然这满足二分的性质,二分答案,根据点距离需要大于等于二分值重新构造新图,则问题变成了:在新图中找出满足所有点对之间的距离 ...

  5. 注意题目条件!!! 团问题 HDU 5952

    题目大意:团的定义就是,团内的所有点,两两之间各有一条边,团的大小就是点的个数.现给你一个n个点,m条边的图.问,该图中有多少点的个数为s的团. (题目保证每个点的度数不超过20,n<=100, ...

  6. Maximum Shortest Distance 最大团 二分答案 HDU 3585

    题意:给出n个点   要求取k个点  这k个点中  距离最小的两个点要求距离最大 拿到手看不出是最大团  也看不出是二分答案(第一次用) 因为答案必然存在 一定有一个最值  所以用二分答案来做 最大距 ...

  7. hdu 5556 Land of Farms 最大团+暴力

    Land of Farms Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Tot ...

  8. hdu 5952 Counting Cliques 求图中指定大小的团的个数 暴搜

    题目链接 题意 给定一个\(n个点,m条边\)的无向图,找出其中大小为\(s\)的完全图个数\((n\leq 100,m\leq 1000,s\leq 10)\). 思路 暴搜. 搜索的时候判断要加进 ...

  9. HDU——PKU题目分类

    HDU 模拟题, 枚举1002 1004 1013 1015 1017 1020 1022 1029 1031 1033 1034 1035 1036 1037 1039 1042 1047 1048 ...

  10. 【转载】图论 500题——主要为hdu/poj/zoj

    转自——http://blog.csdn.net/qwe20060514/article/details/8112550 =============================以下是最小生成树+并 ...

随机推荐

  1. aes python加密

    # *_*coding:utf-8 *_* #AES-demo import base64 from Crypto.Cipher import AES ''' 采用AES对称加密算法 ''' # st ...

  2. matplotlib删除地图投影上的等值线及风场

    [前言]最近在编写一个气象应用程序,用来显示某一时刻某一地区的气温等值线和风场,程序主要用到了第三方库matplotlib及Basemap.在编写的过程中发现,如果不进行擦除操作直接绘制新的等值线或风 ...

  3. SpringMVC框架并发时出现id变成另外一个用户id问题

    今天测试写的代码,出现了在用一个账户登录操作的时候,操作记录的是另外一个id. 经过查找网上的解决方案确认了问题:在controller里面定义了一个userid属性,每次都通过userid传输值.然 ...

  4. [BZOJ4556][Tjoi2016&Heoi2016]字符串 后缀数组+主席树

    4556: [Tjoi2016&Heoi2016]字符串 Time Limit: 20 Sec  Memory Limit: 128 MB Description 佳媛姐姐过生日的时候,她的小 ...

  5. Unity使用C#实现简单Scoket连接及服务端与客户端通讯

    简介: 网络编程是个很有意思的事情,偶然翻出来很久之前刚开始看Socket的时候写的一个实例,贴出来吧 Unity中实现简单的Socket连接,c#中提供了丰富的API,直接上代码. 服务端代码: [ ...

  6. 3Sum - LeetCode

    目录 题目链接 注意点 解法 小结 题目链接 3Sum - LeetCode 注意点 和two sum那道题不一样的是这题返回的是具体的数字,不是下标 解法 解法一:将每个数字都作为target,剩下 ...

  7. Android O新特性和行为变更总结zz

    https://mp.weixin.qq.com/s/Ezfm-Xaz3fzsaSm0TU5LMw Android O 行为变更https://developer.android.google.cn/ ...

  8. [USACO18OPEN]Out of Sorts P 冒泡排序理解之二

    题目描述 Bessie把快速排序和冒泡排序混在了一起 给一个伪快排的代码: 冒泡: bubble_sort_pass (A) { to length(A)- ], swap A[i] and A[i+ ...

  9. .net mvc 一个Action的 HttpGet 和 HttpPost

    http://www.cnblogs.com/freeliver54/p/3747836.html 本文转自:http://stackoverflow.com/questions/11767911/m ...

  10. D. Vitya and Strange Lesson Codeforces Round #430 (Div. 2)

    http://codeforces.com/contest/842/problem/D 树 二进制(路径,每个节点代表一位) #include <cstdio> #include < ...