E - Counting Cliques HDU - 5952
题意:
给你n个点,m个边,还有一个s,问这个图中有多少个等于s的点集可以组成一个完全图
题解:
这题。。直接暴力搜索就行
分析复杂度的时候,应该考虑只有1000条边,所以我最多才枚举1000条边,100个点,再加上每次判断最多1e6的时间复杂度,再加一些剪枝,肯定不会超时的
如何避免搜索重复呢?我们规定起点标号小于终点标号,这样边就成为单向边,不会反过来跑,这样实现剪枝且避免重复计算
具体实现为:我依次枚举每个点在完全图内,然后从这个点开始出发跑,每到一个新点,判断他是否与已经存的所有点都有边,都有边说明他也在完全图中,加入,然后继续,直到满足s个点集,然后return,继续跑
详细看代码
代码:
#include<bits/stdc++.h>
#define debug(a,b) printf("%s = %d\n",a,b);
typedef long long ll;
using namespace std;inline int read(){int s=0,w=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();//s=(s<<3)+(s<<1)+(ch^48);return s*w;
}
int n,m,s;
const int maxn=130;
vector<int>vec[maxn];
bool edge[maxn][maxn];
int tot=0;
int vis[maxn];
void dfs(int x){if(x==s){tot++;return ;}int pre=vis[x];for(int i=0;i<vec[pre].size();i++){int f=1;int v=vec[pre][i];for(int j=1;j<=x;j++){//与之前已经加入连通图的点查看是否都有边 if(edge[v][vis[j]]==0){f=0;break;}}if(f==1){vis[x+1]=v;dfs(x+1);} }
}
int main()
{int t;scanf("%d",&t);while(t--){tot=0;memset(edge,0,sizeof(edge));scanf("%d%d%d",&n,&m,&s);for(int i=1;i<=m;i++){int u,v;scanf("%d%d",&u,&v);edge[u][v]=1;edge[v][u]=1;if(u<v) vec[u].push_back(v);else vec[v].push_back(u);}for(int i=1;i<=n;i++){memset(vis,0,sizeof(vis));vis[1]=i;dfs(1);}printf("%d\n",tot);for(int i=1;i<=100;i++)vec[i].clear();}return 0;}