题目:http://acm.hdu.edu.cn/showproblem.php?pid=5313
题意:
给出n个顶点,m条边,问最多添加多少条边使之构成一个完全二分图
存储结构:
bitset 【用法详情:http://blog.csdn.net/piaocoder/article/details/47177891】
用时:624ms
思路:
二分图的总边数即:n*m(假设一个有n个点,另一个有m个点)
题目是给出总共的点数为n,间接求最大的边数
想到一个小学题:给出长度为n的绳子,将其分为两截,使以这两截长度作为长和宽的矩形面积最大,当然,就是平分喽
虽然,此题不一定和小学题一模一样,但是要想使得分出的n和m乘积最大,必须使n和m尽可能相近,没问题吧。
然后我们用一个并查集先分出各个连通图,再做相应的处理即可,详见注释
代码如下:
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<bitset> 5 using namespace std; 6 const int v_N = 10010; //总结点数 7 bitset<v_N> Bit; //允许多少条边构成一个集合,比如:允许一个点构成一个集合,那么Bit[1]为真,否则为假 8 int n, m, group, fa[v_N], color[v_N], part_num[v_N][2]; 9 //fa:父亲; color:染色 part_num:同一个集合(并查集得到)中各个颜色所拥有的结点个数 10 int find(int x) 11 { 12 if (x == fa[x]) 13 return x; 14 int t = fa[x]; 15 fa[x] = find(fa[x]); 16 color[x] ^= color[t]; //当前与父亲异或,刷新颜色 17 return fa[x]; 18 } 19 void solve() 20 { 21 for (int i = 1; i <= n; ++i) 22 Bit[i] = 0; 23 Bit[0] = 1; 24 for (int i = 1; i <= n; ++i) //统计 25 part_num[find(i)][color[i]]++; 26 for (int i = 1; i <= n; ++i) 27 if (i == fa[i]) //说明一个集合结束了,刷新Bit 28 Bit = (Bit << part_num[i][0]) | (Bit << part_num[i][1]); 29 int _max = 0; 30 for (int i = n / 2 - 1; i <= n / 2 + 1; ++i) //遍历半数左右即可!! 剪枝 31 if (Bit[i]) 32 _max = max(_max, i*(n - i) - m); 33 printf("%d\n", _max); 34 } 35 36 int main() 37 { 38 scanf("%d", &group); 39 while (group--) 40 { 41 scanf("%d%d", &n, &m); 42 for (int i = 1; i <= n; ++i) 43 fa[i] = i, color[i] = part_num[i][0] = part_num[i][1] = 0; 44 for (int i = 0; i < m; ++i) 45 { 46 int x, y, fx, fy; 47 scanf("%d%d", &x, &y); 48 fx = find(x), fy = find(y); 49 if (fx == fy) 50 continue; 51 fa[fx] = fy; 52 color[fx] = 1 ^ color[x] ^ color[y]; //保证同一条边或不同一集合颜色不同,初始为0,所以用1异或 53 } 54 solve(); 55 } 56 }
感谢您的阅读,生活愉快~