hdu 5952 Counting Cliques 暴搜+剪枝优化(邻接链表建图,邻接矩阵重建图,另类ac哦)

题目描述:

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亚洲区沈阳站-重现赛(感谢东北大学)

题目大意:

给你一个n个点,m条边的图,问你这个图中有多少个点数为s的完全图

题解:

正常暴力去一个点一个点的去暴搜,一定会超时,所以我们必须加一些剪枝。我的思路就是让我们构成的团中所有的点呈升序(这样可以避免重复团的出现)。还要在搜的时候判断一下此时这个点与之前存的点有没有边,如果其中有一个没有那就回溯不往下继续搜。刚开始我用的是邻接链表建图,但是正好我输入的样例所有的边都是1 2,1 3,1 4这样升序存的,当邻接链表遍历的时候就会从4,3,2往下遍历,导致之前我说团中成升序的情况恰好可以通过。但是一旦你的测试样例是这样输入的话1 4,1 3,1 2,我们下面代码的那个剪枝就会导致bug(因为这个导致wa了好久,以至于比赛的时候没有ac,还是菜啊)。所以我的想法就是将边排序,用邻接矩阵来存,在dfs时倒着将所连的点遍历,这样就不会wa了。  这个方法有点复杂,不向别人的姿势优美,而且对比别人ac的我的时间要比他们慢,但绝对原创哦。

代码如下(有注释可以好好参考一下):

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<algorithm>
#include<queue>
#include<stack>
#include<vector>
#include<set>
#include<map>
#include<list>
#define mem(x,y)memset(x,y,sizeof(x))
#define max(a,b)(a)>(b)?(a):(b)
#define min(a,b)(a)<(b)?(a):(b)
#define INF 0x1f1f1f1f
#define eps 1e-10
#define M 10000000007
using namespace std;
const int maxn=1005;
struct qxw
{
    int point,next;
};//  邻接链表
vector <int> G[maxn];//   邻接矩阵
qxw a[maxn*10];
int n,m,s,tot,sum,ss;
int head[maxn];
int vis[maxn][maxn];//  标记两点之间是否有边
int b[maxn];//  这个数组是每次团中存的点
int c[maxn];
int V[maxn];
void init()//   初始化函数
{
    int i;
    for(i=0;i<=n;i++)
    {
        G[i].clear();
    }
    mem(b,0);
    mem(V,0);
    mem(head,-1);
    mem(vis,0);
    tot=0;
}
void add(int xx,int yy)//   邻接链表加边
{
    a[tot].point=yy;
    a[tot].next=head[xx];
    head[xx]=tot++;
}
void dfs(int u,int num,int bnt)//  暴搜找团
{
    if(num>s)return;
    int i,j;
    b[bnt]=u;
    V[u]=1;
    for(i=0;i<bnt;i++)//  剪枝的一部分:
    {                 //判断此时这个点和之前存在b数组的点有没有边相连
        if(!vis[u][b[i]]||!vis[b[i]][u])//如果无边直接回溯
        {
            return ;
        }
    }
    if(num==s)//  如果可以构成一个团,sum++
    {
        sum++;
        return ;
    }
    for(i=G[u].size()-1;i>=0;i--)
    {
        int v=G[u][i];
        if(v<u)return ;//  这里也是一个剪枝,防止出现重复团的情况,让所有的团中的点呈升序排列
        if(!V[v])
        {
            dfs(v,num+1,bnt+1);
            V[v]=0;
        }
    }
}
int main()
{
    int T,i,j;
    scanf("%d",&T);
    while(T--)
    {
        init();
        scanf("%d %d %d",&n,&m,&s);
        int x,y;
        for(i=0;i<m;i++)
        {
            scanf("%d %d",&x,&y);
            if(vis[x][y]||vis[y][x])//   避免重边
            {
                continue;
            }
            add(x,y);//刚开始使用邻接链表建图
            add(y,x);
            vis[x][y]=1,vis[y][x]=1;//  有边的话标记为一
            vis[x][x]=1,vis[y][y]=1;
        }
        int cnt;
        //  下面代码实现的是:遍历所有边,将每个点相连的点从小到大,用邻接矩阵重新建图
        for(i=1;i<=n;i++)
        {
            cnt=0;
            for(j=head[i];j!=-1;j=a[j].next)
            {
                c[cnt++]=a[j].point;
            }
            sort(c,c+cnt);
            for(j=0;j<cnt;j++)
            {
                G[i].push_back(c[j]);
            }
        }
        sum=0;
        ss=0;
        //  为了让所有团中的点呈升序,所以(n-s+1)后面的点没有必要在遍历
        for(i=1;i<=n-s+1;i++)
        {
            mem(V,0);
            dfs(i,1,0);
        }
        printf("%d\n",sum);
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
资源包主要包含以下内容: ASP项目源码:每个资源包中都包含完整的ASP项目源码,这些源码采用了经典的ASP技术开发,结构清晰、注释详细,帮助用户轻松理解整个项目的逻辑和实现方式。通过这些源码,用户可以学习到ASP的基本语法、服务器端脚本编写方法、数据库操作、用户权限管理等关键技术。 数据库设计文件:为了方便用户更好地理解系统的后台逻辑,每个项目中都附带了完整的数据库设计文件。这些文件通常包括数据库结构、数据表设计文档,以及示例数据SQL脚本。用户可以通过这些文件快速搭建项目所需的数据库环境,并了解各个数据表之间的关系和作用。 详细的开发文档:每个资源包都附有详细的开发文档,文档内容包括项目背景介绍、功能模块说明、系统流程、用户界面设计以及关键代码解析等。这些文档为用户提供了深入的学习材料,使得即便是从零开始的开发者也能逐步掌握项目开发的全过程。 项目演示与使用指南:为帮助用户更好地理解和使用这些ASP项目,每个资源包中都包含项目的演示文件和使用指南。演示文件通常以视频或文形式展示项目的主要功能和操作流程,使用指南则详细说明了如何配置开发环境、部署项目以及常见问题的解决方法。 毕业设计参考:对于正在准备毕业设计的学生来说,这些资源包是绝佳的参考材料。每个项目不仅功能完善、结构清晰,还符合常见的毕业设计要求和标准。通过这些项目,学生可以学习到如何从零开始构建一个完整的Web系统,并积累丰富的项目经验。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值