传送门: 洛谷  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. [学习]Windows server 使用控制台时容易卡死的解决方法

    公司使用Windows server 下面的 cmd 命令行 控制台打开某一个 bat 文件的方式 进行后台使用.. 但是经常发现在winserver 2016 时 遇到卡死的情况, 今天中午我再进行 ...

  2. 微信小程序组件 模块化错和叹号

    wxml 页面 <import src="/pages/lianxi/lianxi.wxml" />  //引入文件 <view style='position: ...

  3. APP 测试 与 WEB 测试的本质区别

    单纯从功能测试的层面上来讲的话,APP 测试.web 测试 在流程和功能测试上是没有区别的 根据两者载体不一样,则区别如下: 1.系统结构方面 web项目,b/s架构,基于浏览器的:web测试只要更新 ...

  4. 【bzoj4591】[Shoi2015]超能粒子炮·改 Lucas定理

    题目描述 曾经发明了脑洞治疗仪&超能粒子炮的发明家SHTSC又公开了他的新发明:超能粒子炮·改--一种可以发射威力更加强大的粒子流的神秘装置.超能粒子炮·改相比超能粒子炮,在威力上有了本质的提 ...

  5. python参数传递方式

    原文地址:http://www.cnblogs.com/zhaopengcheng/p/5492183.html python中一切皆对象,函数中参数传递的是对象的引用. 1在函数中改变变量指向的对象 ...

  6. 理解Restful api的意义

    RESTful API 只是API的设计规范或者是一套设计理论. 单就URL和Method这两个点,你可以这样理解: URL 是用来唯一标示一个互联网资源的,而 Method 是用来标识当前请求对该资 ...

  7. Linux进程间通信(消息队列/信号量+共享内存)

    写在前面 不得不说,Deadline果真是第一生产力.不过做出来的东西真的是不堪入目,于是又花了一早上重写代码. 实验内容 进程通信的邮箱方式由操作系统提供形如 send()和 receive()的系 ...

  8. BZOJ4727 [POI2017]Turysta 【竞赛图哈密顿路径/回路】

    题目链接 BZOJ4727 题解 前置芝士 1.竞赛图存在哈密顿路径 2.竞赛图存在哈密顿回路,当且仅当它是强联通的 所以我们将图缩点后,拓扑排序后一定是一条链,且之前的块内的点和之后块内的点的边一定 ...

  9. java多线程 --ConcurrentLinkedQueue 非阻塞 线程安全队列

    ConcurrentLinkedQueue是一个基于链接节点的无界线程安全队列,它采用先进先出的规则对节点进行排序,当我们添加一个元素的时候,它会添加到队列的尾部:当我们获取一个元素时,它会返回队列头 ...

  10. [THUSC 2016] 补退选 (Trie树)

    link $solution:$ $Trie$树很显然吧,那么如何去处理每次询问.对于$Trie$树的每个节点放一个$vector$表示其若有$v$个人的最小时间. #include<iostr ...