1. 程式人生 > >hdu5952 Counting Cliques 技巧dfs

hdu5952 Counting Cliques 技巧dfs

hdu push_back one 完整 for online 下一個 兩個 math

題意:一個有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\n", ans); 103 } 104 105 return 0; 106 }
View Code

hdu5952 Counting Cliques 技巧dfs