题意:一个有N个点M条边的图,球其中由S个点构成的团的个数。一个团是一个完全子图。
没有什么好办法,只有暴力深搜,但是这里有一个神奇的操作:将无向图转为有向图:当两个点编号u<v时才有边u->v,这样的好处是一张完全图只有从最小编号开始深搜的时候才会搜完整张完全图(本来完全图从其中任意一个节点进入都是没有区别的),因为假如v1 < v2,并且v1,v2在同一完全图中,则v2只会走到编号更大的点,这样每张大小为S的完全图只有一条固定的路,所以不会重复。从1~N个点每个点开始dfs,这样即使两个完全图的点集有交集,但因为每张完全图的编号最小的那个点都会被遍历到,所以不会遗漏。
然后问题就是怎么搜了,考虑这样的情况,v1,v2...vn构成一个完全图,并且v0与v1连了一条有向边。那会不会出现这样的情况 1:从v0开始dfs,找到了v1~n这个完全图;2:从v1开始dfs,又找到了v1~n这张图。那不是重复了吗?
为了解决这个问题,我们需要保证搜的点都在完全图上,即用path数组记录当前走过的路径,当准备dfs下一个点v时,判断v是不是和前面路径所有点有边相连(所以还是需要记录双向边的图),如果边数量不够或者没有全部相连直接返回,证明这个点不在这个完全图中。
1 #include <iostream> 2 #include <string.h> 3 #include <cstdio> 4 #include <queue> 5 #include <set> 6 #include <stack> 7 #include <math.h> 8 #include <string> 9 #include <algorithm> 10 11 #define SIGMA_SIZE 26 12 #define pii pair<int,int> 13 #define lson rt<<1 14 #define rson rt<<1|1 15 #define lowbit(x) (x&-x) 16 #define fode(i, a, b) for(int i=a; i>=b; i--) 17 #define foe(i, a, b) for(int i=a; i<=b; i++) 18 #define fod(i, a, b) for(int i=a; i>b; i--) 19 #define fo(i, a, b) for(int i=a; i<b; i++) 20 //#pragma warning ( disable : 4996 ) 21 22 using namespace std; 23 typedef long long LL; 24 inline LL LMax(LL a, LL b) { return a>b ? a : b; } 25 inline LL LMin(LL a, LL b) { return a>b ? b : a; } 26 inline LL lgcd(LL a, LL b) { return b == 0 ? a : lgcd(b, a%b); } 27 inline LL llcm(LL a, LL b) { return a / lgcd(a, b)*b; } //a*b = gcd*lcm 28 inline int Max(int a, int b) { return a>b ? a : b; } 29 inline int Min(int a, int b) { return a>b ? b : a; } 30 inline int gcd(int a, int b) { return b == 0 ? a : gcd(b, a%b); } 31 inline int lcm(int a, int b) { return a / gcd(a, b)*b; } //a*b = gcd*lcm 32 const LL INF = 0x3f3f3f3f3f3f3f3f; 33 const LL mod = 1e9+7; 34 const double eps = 1e-8; 35 const int inf = 0x3f3f3f3f; 36 const int maxk = 1e5+5; 37 const int maxm = 510*510; 38 const int maxn = 110; 39 40 int n, m, s, ans; 41 int path[maxn]; 42 bool g[maxn][maxn]; 43 vector<int> vv[maxn]; 44 45 void init() 46 { 47 cin >> n >> m >> s; 48 49 int x, y; ans = 0; 50 memset(g, 0, sizeof(g)); 51 memset(path, 0, sizeof(path)); 52 foe(i, 1, n) vv[i].clear(); 53 foe(i, 1, m) 54 { 55 scanf("%d %d", &x, &y); 56 g[x][y] = g[y][x] = true; 57 vv[Min(x,y)].push_back(Max(x, y)); 58 } 59 } 60 61 void dfs(int x, int d) 62 { 63 if (d == s) { ans++; return; } 64 //if (vv[x].size()+d < s) return; 65 66 for ( int i = 0; i < vv[x].size(); i++ ) 67 { 68 int v = vv[x][i]; 69 bool flag = false; 70 71 for ( int i = x; i; i = path[i] ) 72 { 73 if (!g[v][i]) flag = true; 74 if (vv[v].size()+1+d < s) flag = true; 75 if (flag) break; 76 } 77 78 if (!flag) 79 { 80 path[v] = x; 81 dfs(v, d+1); 82 } 83 } 84 } 85 86 int main() 87 { 88 89 #ifndef ONLINE_JUDGE 90 freopen("input.txt", "r", stdin); 91 #endif 92 93 int T; cin >> T; 94 while(T--) 95 { 96 init(); 97 foe(i, 1, n) 98 { 99 path[i] = 0; 100 dfs(i, 1); 101 } 102 printf("%d ", ans); 103 } 104 105 return 0; 106 }