最大团 HDU-1530
题目描述
• 给定一个图 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. 搜索 2.
BornKerbosch算法 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的更多相关文章
- hdu 1530 最大团模板
说明摘自:pushing my way 的博文 最大团 通过该博主的代码,总算理解了最大团问题,但是他实现时的代码效率却不算太高.因此在最后献上我的模板.加了IO优化目前的排名是: 6 yejinru ...
- hdu 1530 Maximum Clique
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1530 题目分类:最大团问题 DP + DFS 代码: #include<bits/stdc++. ...
- hdu 1530 Maximum Clique (最大包)
Maximum CliqueTime Limit: 20000/10000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)T ...
- hdu 3585 二分+最大团
题目:给出平面上n个点,现在找m个点,并且使得这m个点最近的两个最远. 分析:显然这满足二分的性质,二分答案,根据点距离需要大于等于二分值重新构造新图,则问题变成了:在新图中找出满足所有点对之间的距离 ...
- 注意题目条件!!! 团问题 HDU 5952
题目大意:团的定义就是,团内的所有点,两两之间各有一条边,团的大小就是点的个数.现给你一个n个点,m条边的图.问,该图中有多少点的个数为s的团. (题目保证每个点的度数不超过20,n<=100, ...
- Maximum Shortest Distance 最大团 二分答案 HDU 3585
题意:给出n个点 要求取k个点 这k个点中 距离最小的两个点要求距离最大 拿到手看不出是最大团 也看不出是二分答案(第一次用) 因为答案必然存在 一定有一个最值 所以用二分答案来做 最大距 ...
- hdu 5556 Land of Farms 最大团+暴力
Land of Farms Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)Tot ...
- hdu 5952 Counting Cliques 求图中指定大小的团的个数 暴搜
题目链接 题意 给定一个\(n个点,m条边\)的无向图,找出其中大小为\(s\)的完全图个数\((n\leq 100,m\leq 1000,s\leq 10)\). 思路 暴搜. 搜索的时候判断要加进 ...
- HDU——PKU题目分类
HDU 模拟题, 枚举1002 1004 1013 1015 1017 1020 1022 1029 1031 1033 1034 1035 1036 1037 1039 1042 1047 1048 ...
- 【转载】图论 500题——主要为hdu/poj/zoj
转自——http://blog.csdn.net/qwe20060514/article/details/8112550 =============================以下是最小生成树+并 ...
随机推荐
- aes python加密
# *_*coding:utf-8 *_* #AES-demo import base64 from Crypto.Cipher import AES ''' 采用AES对称加密算法 ''' # st ...
- matplotlib删除地图投影上的等值线及风场
[前言]最近在编写一个气象应用程序,用来显示某一时刻某一地区的气温等值线和风场,程序主要用到了第三方库matplotlib及Basemap.在编写的过程中发现,如果不进行擦除操作直接绘制新的等值线或风 ...
- SpringMVC框架并发时出现id变成另外一个用户id问题
今天测试写的代码,出现了在用一个账户登录操作的时候,操作记录的是另外一个id. 经过查找网上的解决方案确认了问题:在controller里面定义了一个userid属性,每次都通过userid传输值.然 ...
- [BZOJ4556][Tjoi2016&Heoi2016]字符串 后缀数组+主席树
4556: [Tjoi2016&Heoi2016]字符串 Time Limit: 20 Sec Memory Limit: 128 MB Description 佳媛姐姐过生日的时候,她的小 ...
- Unity使用C#实现简单Scoket连接及服务端与客户端通讯
简介: 网络编程是个很有意思的事情,偶然翻出来很久之前刚开始看Socket的时候写的一个实例,贴出来吧 Unity中实现简单的Socket连接,c#中提供了丰富的API,直接上代码. 服务端代码: [ ...
- 3Sum - LeetCode
目录 题目链接 注意点 解法 小结 题目链接 3Sum - LeetCode 注意点 和two sum那道题不一样的是这题返回的是具体的数字,不是下标 解法 解法一:将每个数字都作为target,剩下 ...
- Android O新特性和行为变更总结zz
https://mp.weixin.qq.com/s/Ezfm-Xaz3fzsaSm0TU5LMw Android O 行为变更https://developer.android.google.cn/ ...
- [USACO18OPEN]Out of Sorts P 冒泡排序理解之二
题目描述 Bessie把快速排序和冒泡排序混在了一起 给一个伪快排的代码: 冒泡: bubble_sort_pass (A) { to length(A)- ], swap A[i] and A[i+ ...
- .net mvc 一个Action的 HttpGet 和 HttpPost
http://www.cnblogs.com/freeliver54/p/3747836.html 本文转自:http://stackoverflow.com/questions/11767911/m ...
- D. Vitya and Strange Lesson Codeforces Round #430 (Div. 2)
http://codeforces.com/contest/842/problem/D 树 二进制(路径,每个节点代表一位) #include <cstdio> #include < ...