传送门: 洛谷  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. [转帖]学习一下centos7 新地方

    总结的挺好  copy一下 慢慢学习: http://blog.itpub.net/312079/viewspace-2214440/ Centos7 单用户模式 centos7里不再有0-6启动级别 ...

  2. vi 基础配置

    " Configuration file for vim " CVE-2007-2438 " Normally we use vim-extensions. If you ...

  3. python web调用docker-py

    在 /etc/init.d/docker的start()函数末尾加入:chmod 777 /var/run/docker.sock 否则web程序会没有权限去操作  

  4. Struts1 工作流程

    一个老项目的维护 , 需要学习一下 Struts1. struts1运行步骤 1.项目初始化:项目启动时加载 web.xml,struts1 的总控制器 ActionServlet 是一个 Servl ...

  5. HDU4791_Alice's Print Service

    全场最水题. 保留打印a[i]份分别需要的钱,从后往前扫一遍,保证取得最优解. 查找的时候,二分同时判断最小值即可. 注意初值的设定应该设定为long long 的无穷大. #include < ...

  6. js判断浏览器语言实现网站国际化

    一般国际化的网站至少是有中.英文两种语言的,然后就是在不同的语言环境下使用不同的语言页面. 1.实现原理 一般实现这种功能的方法,无非就是两种, 第一种,判断浏览器语言类型: 第二种,判断ip所属国家 ...

  7. D-Separation(D分离)-PRML-8.22-Graphical Model 五 18 by 小军

    D-Separation(D分离)-PRML-8.22-Graphical Model 五18by 小军   一.引言 在贝叶斯网络的学习过程中,经常会遇到(D-Separation)D-分离这个概念 ...

  8. Springboot+Thymeleaf框架的button错误

    ---恢复内容开始--- 在做公司项目时,遇到了一个Springboot+Thymeleaf框架问题: 使用框架写网站时,没有标明type类型的button默认成了‘submit’类型,每次点击按钮都 ...

  9. Extend to Palindrome UVA - 11475(补成回文串)

    题意: 就是用最少的字符把原字符串补成回文串 解析: emm/.../网上都是用kmp和后缀数组做的 我没想到这俩的思路...emmm... 想到了exkmp的  就是原串和逆串匹配一下  注意要保证 ...

  10. ajax请求提交到controller后总是不成功

    最近在做实习时,点击查询时在js中发送ajax请求到controller后台,但是无论怎么样都不成功,请求地址是正确的,因为在后台用system.out.println输出有值,并且也确实return ...