Counting Cliques HDU - 5952 (暴力+剪枝)

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
题目大意:
给出一个图,然后问你有多少个节点数为s的完全子图; 题目思路:
首先我们肯定去想如何去判断是否为完全子图,我们可以想到从某一个点出发,然后对于这个点去扩展,把有可能为完全图中的节点加入到数组中,然后对于扩展出的节点再去扩展节点,如果对于这个点如果跟集合中的点都联通,那么我们就把它加入集合,并且用它去扩展,重复这个过程,直到集合内的点有s个
这样子思路是没错的,但是会超时,而且有很多重复的,其实我们可以只用建单向边,并且是从小到大的边,然后还是保存一下点之间的联通关系,这样能减很多复杂度,为什么这样子可行呢,因为观察我们去寻找完全子图得过程,我们只用保证子图的连通性就行了,这样子就可以减一半的复杂度,那么为什么要连从小到大的呢,因为我们遍历顺序就是从小到大的
ac代码:
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<sstream>
#include<cmath>
#define LL long long
#define INF 0x3f3f3f3f
using namespace std;
const int maxn = 100+5;
int head[maxn];
int vis[maxn];
int tot;
int T;
int n,m,s;
int mp[maxn][maxn];
void init()
{
    memset(head,-1,sizeof(head));
    tot = 0;
}
int du[maxn];

struct node
{
    int u,v;
    int net;
}E[maxn*10];
void build(int u,int v){
    E[tot].u =u ;
    E[tot].v = v;
    E[tot].net = head[u];
    head[u] = tot++;
}
LL ans;
int a[21];
void dfs(int u,int sum,int fa)
{
    if(sum==s){
          //  cout<<fa<<--endl;
        ans++;
        return;
    }
    if(du[u]<s-1)
        return;
    for(int i = head[u];~i;i = E[i].net){
        int to = E[i].v;
        if(to==fa) continue;
        int falg = 1;
        for(int j = 0;j<sum;j++){
            if(mp[a[j]][to]==-1){
                falg = 0;
                break;
            }
        }
        if(falg){
            a[sum++] = to;
            dfs(to,sum,u);
            sum--;
        }
    }
}
int main()
{
    scanf("%d",&T);
    while(T--){
        init();
        scanf("%d%d%d",&n,&m,&s);
        memset(du,0,sizeof(du));
        memset(mp,-1,sizeof(mp));
        ans = 0;
        for(int i = 0;i<m;i++){
            int a,b;
            scanf("%d%d",&a,&b);
            if(a>b) swap(a,b);
            build(a,b);
            mp[a][b] = 1;
            mp[b][a] = 1;
            du[a]++;
            du[b]++;
        }
        for(int i = 1;i<=n;i++){
            a[0] = i;
          //  cout<<"fuck"<<endl;
            dfs(i,1,-1);
        }
       // cout<<ans<<endl;
        printf("%d\n",ans);
    }
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值