Bipartite Graph hdu 5313 bitset 并查集 二分图

题目: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 }

感谢您的阅读,生活愉快~

原文地址:https://www.cnblogs.com/lv-anchoret/p/8471713.html

时间: 2024-07-31 21:52:39

Bipartite Graph hdu 5313 bitset 并查集 二分图的相关文章

Hdu 2473(并查集删除操作) Junk-Mail Filter

有木有很吊 加强 加强版   啊  ,看了都不敢做了   ,后来先做了食物链这个我还是看过的,但还是A不掉,没明白神魔意思 ,总而言之,大牛的博客是个好东西,我就那么看了一下,还是不懂怎莫办啊,哎,就那样就A掉了....... 今天我们来谈一下这个并查集的删除操作,根据我对大牛的理解啊,这个并查集的删除操作并不是把原来的节点删除掉,而是用一个替身替掉,现在的这个点只是用作桥梁的作用,即是无用的,del  ,,,del  ,,,,删除,那些被删掉的就从n开始给他们一个地址,然后即如下代码所示 #i

HDU 4496 D-City(并查集,逆思维)

题目 熟能生巧...常做这类题,就不会忘记他的思路了... //可以反过来用并查集,还是逐个加边,但是反过来输出...我是白痴.....又没想到 //G++能过,C++却wa,这个也好奇怪呀... #include<stdio.h> #include<string.h> int fx,fy,r,bin[10010]; int x[100010],y[100010],n,m,i,count,ans[100010],j; int find(int x) { //改成这样就不会超时了么好

HDU 1272 简单并查集

小希的迷宫 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 24915    Accepted Submission(s): 7641 Problem Description 上次Gardon的迷宫城堡小希玩了很久(见Problem B),现在她也想设计一个迷宫让Gardon来走.但是她设计迷宫的思路不一样,首先她认为所有的通道都应该是双

hdu 3038 (并查集)

题目大意: 给出m个询问,问[l,r]之间的和   ,求出有多少次询问不和之前的矛盾的. 思路分析: 用并查集记录当前节点到根节点的和. #include <cstdio> #include <iostream> #include <cstring> #include <algorithm> #define maxn 222222 using namespace std; int set[maxn]; int sum[maxn]; int find(int

hdu 4496 D-City 并查集

D-City Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65535/65535 K (Java/Others) Total Submission(s): 2317    Accepted Submission(s): 814 Problem Description Luxer is a really bad guy. He destroys everything he met. One day Luxer went to D-

hdu 3081(二分+并查集+最大流||二分图匹配)

Marriage Match II Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 3558    Accepted Submission(s): 1158 Problem Description Presumably, you all have known the question of stable marriage match. A

Farm Irrigation HDU - 1198 (并查集)

Farm Irrigation HDU - 1198 题意:给11种管道,问草地最少需要打多少个井才可以全部灌溉. 把每种管道的状态用二进制表示一下,然后对每一块草地,判断能否和上面或者左面的草地的管道连接. 然后并查集搞一下. 1 #include <bits/stdc++.h> 2 using namespace std; 3 const int maxn=55; 4 5 int g[12]={10,9,6,5,12,3,11,14,7,13,15}; 6 int f[maxn*maxn]

HDU 5441 Travel 并查集

HDU 5441 Travel 题意:一张无向图,q个查询,对于每个x,有多少对点之间的路径中最长的一条路不大于x. 思路:比赛时王秋平写的,我补下题.这题也比较简单,将边排序,从小到大加到并查集,对查询也排序,从小到大对于每个查询把不大于x的边加到并查集,用cnt[y]记录以y为根的连通块有多少节点,那么在连通块发生 变化时,ans=2 * cnt[x] * cnt[y] 1 #include <iostream> 2 #include <cstdio> 3 #include &

HDU 2818 (矢量并查集)

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=2818 题目大意:每次指定一块砖头,移动砖头所在堆到另一堆.查询指定砖头下面有几块砖头. 解题思路: [HDU数据有问题],数据从0开始,且给定n块砖头(比如1000),数据会有第1005块砖头,导致访问越界. [解决方案],并查集初始化范围改为0~maxn(30005) 由于只给定一块砖头,却要移动所在堆.所以需要并查集维护所在堆. p[x]=y,即x所在堆的堆底是y,注意此时并查集是有方向的.