zoukankan      html  css  js  c++  java
  • HDU5952 Counting Cliques计算完全图的个数 巧妙构图+dfs

    题目传送门

          题目大意:给出n个点,m条无向边,让你计算这幅母图中有几个大小为s的完全图。

           完全图的意思是任意一个点都和其他点直接相连,完全图的大小指的就是完全图点的个数。

          思路:比较巧妙的构图方式。我们会很自然地想到用dfs来找环,然后记录路径,判断是否成完全图,但是由于题目给的是双向边,如果直接构图的话,就会导致出现很多没有必要的情况,重复计算,爆栈超时。

           所以在建图的时候只建从小的点到大的点的单向边,然后对n个点从小到大进行dfs,这样可以既可以保证不会有遗留的情况,也不会重复计算(因为每次走都是从小的点走到大的点,由于是单向边,所以不会回头)。dfs记录路径后,每次放入一个点,把之前路径上的所有点和这个点比较一下,是否是可达的,如果是,则继续dfs下一层,如果不是,则代表这个点无法和路径上的点一起构成完全图,舍弃,找下一条路。

          我存图的方式是链式前向星,这样可以减少遍历的次数,而判断完全图的方式是直接用邻接矩阵,节约时间。(也就是我存了两幅一样的图)。

          反思:还是一道赛后猛如虎的题目啊,比赛的时候想到用单向边构图,但是当时以为单向边判不了完全图(a能到b,我怎么知道b能不能到a),然后就没想下去了,实际上和答案只差一点点了呀!!

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<algorithm>
    #include<string.h>
    #include<sstream>
    #include<set>
    #include<map>
    #include<vector>
    #include<queue>
    #include<stack>
    #include<bitset>
    #define CLR(a,b) memset(a,b,sizeof(a))
    using namespace std;
    typedef long long ll;
    const int inf=0x3f3f3f3f;
    inline int rd(void) {
    	int x=0; int f=1;char s=getchar();
    	while(s<'0'||s>'9') {	if(s=='-')f=-1;	s=getchar();}
    	while(s>='0'&&s<='9') {	x=x*10+s-'0';s=getchar();}
    	x*=f;return x;
    }
    int n,m,s,ans;
    int head[1010],tot,lu[20];
    struct edge{
    	int v,Next;
    }edge[1010];
    int mp[110][110];
    void init(){
    	CLR(head,-1);
    	tot=0;
    	ans=0;
    	CLR(mp,0);
    }
    void addv(int u,int v){
    	edge[++tot].v=v;
    	edge[tot].Next=head[u];
    	head[u]=tot;
    }
    void dfs(int x,int deep){
    	if(deep==s){
    		ans++;
    		return;
    	}
    	lu[deep]=x;
    	for(int i=head[x];i!=-1;i=edge[i].Next){
    		int flag=1;
    		int v=edge[i].v;
    		for(int j=1;j<deep;j++){
    			if(mp[lu[j]][v]==0){
    				flag=0;
    				break;
    			}
    		}
    		if(flag){
    			dfs(v,deep+1);
    		}
    	}
    	return ;
    }
    int main(){
    	int T;
    	cin>>T;
    	while(T--){
    		scanf("%d%d%d",&n,&m,&s);
    		init();
    		int a,b;
    		for(int i=1;i<=m;i++){
    			scanf("%d%d",&a,&b);
    			if(a>b)swap(a,b);
    			mp[a][b]=1;
    			addv(a,b);
    		}
    		for(int i=1;i<=n;i++){
    			dfs(i,1);
    		}
    		printf("%d
    ",ans);
    	}
    }

    Counting Cliques

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


     

    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

  • 相关阅读:
    组合数学总结
    字符串算法总结
    数据结构总结
    CDQ分治(学习笔记)
    网络流(学习笔记)
    string
    water
    mine
    洛谷 P4035 【球形空间产生器】
    洛谷 P3306 【随机数生成器】
  • 原文地址:https://www.cnblogs.com/mountaink/p/9536704.html
Copyright © 2011-2022 走看看