借鉴了一位大佬:
https://blog.csdn.net/yuanjunlai141/article/details/52972715
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5952
题意:
100个点1000条边的图,问你有多少个s个点的团
分析:
什么叫暴搜????
就是基本不用剪枝,所有情况都搜出来;
题意:给一个无向图,问大小为S的团有多少个,什么叫团?团就是完全图,大小为S的团就是由S个点组成的完全图
怎么写呢??
看题意有100个点,点很少!!!,暴搜一遍吧,但是有可能出现重复啊,怎么做,用一个数组记录已经存在的团的大小,数组是一个由小到大
的数组,即前点要进入团时,判断该节点是否比团内所有点大,这样就避免了重复,判断大小时只需要判断进最后一个点是否比当前点小就行了
所以建图是可以按照 小的点指向大的点得方式建图,这样会少很多不必要的搜索操作。
代码:
#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <string.h>
#include <math.h>
using namespace std;
int n,m,k;
const int maxm=2050,maxn=105;
int mp[maxn][maxn];
struct Edge
{
int to,next;
}edge[maxm];
int tot,head[maxn];
void init()
{
tot=0;
memset(head,-1,sizeof(head));
}
void add(int u,int v)
{
edge[tot].to=v;
edge[tot].next=head[u];
head[u]=tot++;
}
int ans;
void dfs(int a[],int u)
{
/// a 数组保存团
///a[0] 表示团大小
if(a[0]==k)
{
ans++;
return ;
}
int v,flag;
for(int i=head[u];i!=-1;i=edge[i].next)
{
v=edge[i].to;
flag=1;
for(int j=1;j<=a[0];j++)
{
if(mp[v][a[j]]==0)///是否v 与团内所有点都有边
{
flag=0;
break;
}
}
if(flag)///是,全有边
{
a[0]++;
a[a[0]]=v;
dfs(a,v);
a[0]--;
}
}
}
int main()
{
int T;
int u,v;
int sle[maxn];
scanf("%d",&T);
while(T--)
{
scanf("%d%d%d",&n,&m,&k);
memset(mp,0,sizeof(mp));
init();
for(int i=0;i<m;i++)
{
scanf("%d%d",&u,&v);
if(u>v)///建一个小的节点指向大的节点 的图
swap(u,v);
add(u,v);
mp[u][v]=mp[v][u]=1;/// 数组保存好判断是否存在边
}
ans=0;
for(int i=1;i<=n;i++)/// 爆搜,在每个点出发一次
{
sle[0]=1;
sle[1]=i;
dfs(sle,i);
}
printf("%d\n",ans);
}
return 0;
}