【2016-沈阳赛区现场赛-E】暴搜(Counting Cliques,hdu 5952)

来源:互联网 发布:批发商软件 编辑:程序博客网 时间:2024/05/17 08:39

N才100,每个点的度数最多20。就是暗示你可以暴搜啊。

还是思路太死,总想要用些经典算法,比如强连通啊啥的,然后就不会了。

看了题解后自己有一个错误的思路,那就是枚举点,然后找到含有这个点的最大的完全图然后用组合数公式算出答案,最后把这个点删掉。出错在有些团不完全或完全不在完全图内,所以算少了。自己找错能力挺差的,总是纠结于代码哪里写错了,而不思考自己方法的问题,事实上这种自己创造出来的解法最容易出错了。过样例完全没用的,自己造数据试也是得靠运气,要自己分析解法,想想哪里漏了,哪里重了才是王道。你求出了一个完全图,找其中大小为s的团的个数,这个不重不漏。但是团是否全部都在这个完全图内呢?就应该思考。

后来编码时看了别人的代码,用了不习惯的命名方式,结果把邻接矩阵和邻接表写反了,瞬间爆炸。只能说以后尽量用习惯的命名,然后写代码和检查时注意下。


解法:

就是枚举所有点,暴搜所有含有这个点的大小为s的团,更新答案,最后把这个点删去。

暴搜的方法:

含有这个点的团只能含有这个点以及这个点的领点。

那么就对这个点以及这个点的领点进行筛选。首先这个点是肯定要的,然后每个领点可以要或者不要,如果要就得满足要求。进行深度为s的dfs就好了。


代码

#include<bits/stdc++.h>#define maxn 110using namespace std;int N,M,S;int s[maxn];int top;int ans;vector<int>MAP[maxn];bool vis[maxn][maxn];inline bool ok(int x){    for(int i=0;i<top;i++)        if(!(vis[x][s[i]]&&vis[s[i]][x])) return false;    return true;}void dfs(int u,int k){    if(top==S)    {        ans++;        return;    }    if(k>=int(MAP[u].size())||S-top>int(MAP[u].size())-k) return;    if(ok(MAP[u][k]))    {        s[top++]=MAP[u][k];        dfs(u,k+1);        top--;    }    dfs(u,k+1);}int main(){    int T;    scanf("%d",&T);    while(T--)    {        scanf("%d %d %d",&N,&M,&S);        ans=0;        int u,v;        for(int i=1;i<=M;i++)        {            scanf("%d %d",&u,&v);            MAP[u].push_back(v);            MAP[v].push_back(u);            vis[u][v]=vis[v][u]=1;        }        for(int i=1;i<=N;i++)        {            if(int(MAP[i].size())<S-1) continue;            s[top++]=i;            dfs(i,0);            top--;            for(int j=1;j<=N;j++)                vis[i][j]=vis[j][i]=0;            MAP[i].clear();        }        printf("%d\n",ans);    }    return 0;}


0 0
原创粉丝点击