HDU-5952 Counting Cliques(16年ICPC沈阳赛区)(暴力DFS)

本文介绍了一种通过深度优先搜索(DFS)算法来计算无向图中特定大小完全子图数量的方法。该方法利用剪枝技术降低复杂度,并通过实例展示了算法的具体实现过程。

Counting Cliques

Time Limit: 8000/4000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 673    Accepted Submission(s): 264


Problem Description
A clique is a complete graph, in which there is an edge between every pair of the vertices. Given a graph with N vertices and M edges, your task is to count the number of cliques with a specific size S in the graph.
 

Input
The first line is the number of test cases. For each test case, the first line contains 3 integers N,M and S (N ≤ 100,M ≤ 1000,2 ≤ S ≤ 10), each of the following M lines contains 2 integers u and v (1 ≤ u < v ≤ N), which means there is an edge between vertices u and v. It is guaranteed that the maximum degree of the vertices is no larger than 20.
 

Output
For each test case, output the number of cliques with size S in the graph.
 

Sample Input
  
3 4 3 2 1 2 2 3 3 4 5 9 3 1 3 1 4 1 5 2 3 2 4 2 5 3 4 3 5 4 5 6 15 4 1 2 1 3 1 4 1 5 1 6 2 3 2 4 2 5 2 6 3 4 3 5 3 6 4 5 4 6 5 6
 

Sample Output
  
3 7 15
 

Source

2016ACM/ICPC亚洲区沈阳站-重现赛(感谢东北大学) 

题意:给出一个无向图,要求求出点的个数恰好为s的完全子图的数目

题解:(万能的)暴力,具体原理看代码吧= =

#include<cstdio>
#include<algorithm>
#include<string.h>
#include<bitset>
using namespace std;
const int maxn = 105;
int s,ans;
bool mp[maxn][maxn];
/*
这里的dfs看起来很简单,其实包含了一个很大的剪枝:在遍历某个点的时候,已经确定了已经加入团的点是与这个点相连的,还可以知道平均下来每个点的入度不会超过20,
因此整个遍历的复杂度最高是C(9,20)*100
*/
void dfs(int mx,int v[],int cnt){
    int nxt[maxn];
    if(cnt==s) {ans++;return;}
    for(int i=0;i<mx;i++){           //枚举能与点数为cnt的团构成点数为cnt+1的团的所有点
        int len=0;
        for(int j=i+1;j<mx;j++){
            if(mp[v[i]][v[j]]){    //该团的所有"候选点"必须与已经选了的点相连
                nxt[len++]=v[j];
            }
        }
        dfs(len,nxt,cnt+1);
    }
}
int main(){
    int T,n,m,u,v;
   // freopen("in.txt","r",stdin);
    scanf("%d",&T);
    while(T--){
        scanf("%d%d%d",&n,&m,&s);
        memset(mp,0,sizeof(mp));
        for(int i=0;i<m;i++){
            scanf("%d%d",&u,&v);
            mp[u][v]=mp[v][u]=1;
        }
        ans=0;
        int nxt[105];
        for(int i=1;i<=n;i++){      //枚举每个点,这个点必须在所求的团里面,以这个点开始搜索
            int len=0;
            for(int j=i+1;j<=n;j++){
                if(mp[i][j]){      //该团的所有"候选点"必须与已经选了的点相连
                    nxt[len++]=j;
                }
            }
            dfs(len,nxt,1);
        }
        printf("%d\n",ans);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值