传送门: 洛谷  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. 新手向:Vue 2.0 的建议学习顺序

    新手向:Vue 2.0 的建议学习顺序 尤雨溪   1 年前 注:2.0 已经有中文文档 .如果对自己英文有信心,也可以直接阅读英文文档.此指南仅供参考,请根据自身实际情况灵活调整.欢迎转载,请注明出 ...

  2. Pygame - Python游戏编程入门(0) 转

    博客刚开,想把最近学习的东西记录下来,算是一种笔记.最近打算开始学习Python,因为我感觉Python是一门很有意思的语言,很早以前就想学了(碍于懒),它的功能很强大,你可以用它来做科学运算,或者数 ...

  3. 使用 Vagrant 打造跨平台开发环境fffff

    Vagrant 是一款用来构建虚拟开发环境的工具,非常适合 php/python/ruby/java 这类语言开发 web 应用,“代码在我机子上运行没有问题”这种说辞将成为历史. 我们可以通过 Va ...

  4. java实现hash一致性算法

    import org.apache.commons.lang3.RandomUtils; import org.apache.commons.lang3.StringUtils; import jav ...

  5. 抽奖系统 random()

    random() 方法可返回介于 0 ~ 1 之间的一个随机数. document.write(parseInt(10*Math.random())); //输出0-10之间的随机整数document ...

  6. P4645 [COCI2006-2007 Contest#3] BICIKLI

    题意翻译 给定一个有向图,n个点,m条边.请问,1号点到2号点有多少条路径?如果有无限多条,输出inf,如果有限,输出答案模10^9的余数. 两点之间可能有重边,需要看成是不同的路径. 题目描述 A ...

  7. BZOJ 1898: [Zjoi2005]Swamp 沼泽鳄鱼

    1898: [Zjoi2005]Swamp 沼泽鳄鱼 Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 1085  Solved: 604[Submit][S ...

  8. Codeforces 633C Spy Syndrome 2 | Trie树裸题

    Codeforces 633C Spy Syndrome 2 | Trie树裸题 一个由许多空格隔开的单词组成的字符串,进行了以下操作:把所有字符变成小写,把每个单词颠倒过来,然后去掉单词间的空格.已 ...

  9. 洛谷 P1446 [HNOI2008]Cards 解题报告

    P1446 [HNOI2008]Cards 题目描述 小春现在很清闲,面对书桌上的\(N\)张牌,他决定给每张染色,目前小春只有\(3\)种颜色:红色,蓝色,绿色.他询问Sun有多少种染色方案,Sun ...

  10. Linux内核分析实验五

    一.给MenuOS增加time和time-asm命令 1. 克隆并自动编译MenuOS rm menu -rf 强制删除原menu文件 git clone http: cd menumake root ...