「ACM Shenyang Onsite 2016」E.Counting Cliques(dfs暴力+优化)
描述
传送门:我是传送门
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.
输入
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.
输出
For each test case, output the number of cliques with size S in the graph.
样例
输入
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
输出
3
7
15
思路
直接暴力搜索能求得正确答案,但是不优化的话肯定会超时。比赛结束我也没能优化出来…..
赛后看了看EaShion1994的题解才过。最主要的地方还是在其中的2、5两点我没能想到。优化过后便AC了,用了1400+ms
1.限定按照顶点序号上升dfs(完全图性质);
2.存储边从数组转换为vector(题目说顶点的度最多为20,而顶点数最多为100);
3.剪枝N-pre < S-deep,当剩下的点不足以构成定点数为S的完全图;(没太大用)
4.for循环初始化改为memset;(挣扎…)
5.path数组由bool改为int,因为每次递归前都要判断当前点是否和所有已经在路径里面点有边相连,所以要挨个去判断,如果path[i]表示点i是否在路径中,每次都需要执行一个100,如果将path[i]更改为路径中第i个点,每次最多执行10;(关键)
6.删掉了之前用来表示点是否加入路径的数组,因为顶点是严格升序加入路径的,所以这一步判断没必要。
代码
/*
* =============================================
*
* Filename: hdu5952.cpp
*
* Link: http://acm.hdu.edu.cn/showproblem.php?pid=5952
*
* Version: 1.0
* Created: 2018/10/05 18时29分42秒
* Revision: none
* Compiler: g++
*
* Author: 杜宁元 (https://duny31030.top/), duny31030@126.com
* Organization: QLU_浪在ACM
*
* =============================================
*/
#include <bits/stdc++.h>
using namespace std;
#define clr(a, x) memset(a, x, sizeof(a))
#define rep(i,a,n) for(int i=a;i<=n;i++)
#define pre(i,a,n) for(int i=n;i>=a;i--)
#define ll long long
#define max3(a,b,c) fmax(a,fmax(b,c))
#define ios ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0);
const double eps = 1e-6;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
const int MAXN = 105;
vector<int> edge[MAXN];
bool m[MAXN][MAXN];
int T,N,M,S,u,v,p;
int flag;
int tot = 1;
int path[MAXN];
bool check(int now,int step)
{
for(int i = 1;i <= step;i++)
{
if(!m[path[i]][now])
return false;
}
return true;
}
void dfs(int st,int step)
{
if(step == S)
{
p++;
return ;
}
if(N-st < S-step)
return ;
int len = edge[st].size();
for(int j = 0;j < len;j++)
{
if(check(edge[st][j],step))
{
path[tot++] = edge[st][j];
dfs(edge[st][j],step+1);
--tot;
}
}
}
int main()
{
ios
#ifdef ONLINE_JUDGE
#else
freopen("in.txt","r",stdin);
// freopen("out.txt","w",stdout);
#endif
scanf("%d",&T);
while(T--)
{
for(int i = 1;i <= N;i++)
edge[i].clear();
memset(m,0,sizeof m);
scanf("%d %d %d",&N,&M,&S);
for(int i = 1;i <= M;i++)
{
scanf("%d %d",&u,&v);
if(u > v)
swap(u,v);
edge[u].push_back(v);
m[u][v] = 1;
m[v][u] = 1;
}
p = 0;
int tmp = N-S+1;
for(flag = 1;flag <= tmp;++flag)
{
path[tot++] = flag;
dfs(flag,1);
--tot;
}
printf("%d\n",p);
}
fclose(stdin);
// fclose(stdout);
return 0;
}