二分图点染色 BestCoder 1st Anniversary($) 1004 Bipartite Graph

 

题目传送门

 1 /*  2   二分图点染色:这题就是将点分成两个集合就可以了,点染色用dfs做, 剩下的点放到点少的集合里去  3  官方解答:首先二分图可以分成两类点X和Y, 完全二分图的边数就是|X|*|Y|.我们的目的是max{|X|*|Y|}, 并且|X|+|Y|=n.  4  修正:实现多连通块染色,然后贪心选择,将两个集合个数差大的连通块优先添加,能尽量使得un*vn最大  5 */  6 #include <cstdio>  7 #include <algorithm>  8 #include <cstring>  9 #include <vector> 10 #include <map> 11 using namespace std; 12 13 const int MAXN = 1e4 + 10; 14 const int MAXM = 1e5 + 10; 15 const int INF = 0x3f3f3f3f; 16 vector<int> G[MAXN]; 17 int col[2*MAXN]; 18 bool vis[MAXN]; 19 struct Block { //连通块 20 int u, v; 21 bool operator < (const Block &r) const { 22 return u - v > r.u - r.v; 23  } 24 }b[MAXN]; 25 int n, m, un, vn; 26 27 void DFS(int u, int c) { 28 col[c]++; vis[u] = true; 29 for (int i=0; i<G[u].size (); ++i) { 30 int v = G[u][i]; 31 if (vis[v]) continue; 32 DFS (v, c ^ 1); 33  } 34 } 35 36 int main(void) { //BestCoder 1st Anniversary($) 1004 Bipartite Graph 37 //freopen ("D.in", "r", stdin); 38 39 int T; scanf ("%d", &T); 40 while (T--) { 41 scanf ("%d%d", &n, &m); 42 for (int i=1; i<=n; ++i) G[i].clear (); 43 for (int i=1; i<=m; ++i) { 44 int u, v; scanf ("%d%d", &u, &v); 45  G[u].push_back (v); G[v].push_back (u); 46  } 47 48 int color = 0; 49 memset (vis, false, sizeof (vis)); 50 memset (col, 0, sizeof (col)); 51 for (int i=1; i<=n; ++i) { 52 if (vis[i]) continue; 53 DFS (i, color); color += 2; 54  } 55 int cnt = 0; 56 for (int i=0; i<color; i+=2) { 57 b[++cnt].u = col[i]; b[cnt].v = col[i^1]; 58 if (b[cnt].u < b[cnt].v) swap (b[cnt].u, b[cnt].v); 59  } 60 sort (b+1, b+1+cnt); 61 62 un = vn = 0; 63 for (int i=1; i<=cnt; ++i) { 64 if (un <= vn) { 65 un += b[i].u; vn += b[i].v; 66  } 67 else { 68 un += b[i].v; vn += b[i].u; 69  } 70  } 71 printf ("%d\n", un * vn - m); 72  } 73 74 return 0; 75 }

 

你可能感兴趣的:(Graph)