hdu 5313 Bipartite Graph(dfs染色 或者 并查集)

Problem Description

Soda has a bipartite graph with n vertices and m undirected edges. Now he wants to make the graph become a complete bipartite graph with most edges by adding some extra edges. Soda needs you to tell him the maximum number of edges he can add.

Note: There must be at most one edge between any pair of vertices both in the new graph and old graph.

Input

There are multiple test cases. The first line of input contains an integer T (1≤T≤100), indicating the number of test cases. For each test case:

The first line contains two integers n and m, (2≤n≤10000,0≤m≤100000).

Each of the next m lines contains two integer u,v (1≤u,v≤n,v≠u) which means there‘s an undirected edge between vertex u and vertex v.

There‘s at most one edge between any pair of vertices. Most test cases are small.

Output

For each test case, output the maximum number of edges Soda can add.

Sample Input

2
4 2
1 2
2 3
4 4
1 2
1 4
2 3
3 4

Sample Output

2
0

Source

BestCoder 1st Anniversary ($)

 题意:给定一个二分图,要求添加最多的边将原来的二分图变成完全二分图。

解法一:dfs染色:

ans[0]表示左边的图的点个数, ans[1]表示右边的点个数,跑一个dfs,将给定二分图分成两种颜色(color数组用来记录是否染色到),然后没有染色到的就加入左右两边,使得左右两边尽可能接近,相乘 再减掉原来给定边的数量就是能加得最多的边数了。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<vector>
 5 #include<set>
 6 #include<map>
 7 using namespace std;
 8 #define N 10006
 9 int n,m;
10 vector<int>G[N];
11 int color[N];
12 int ans[2];
13 void init()
14 {
15     for(int i=0;i<=n;i++)
16     {
17         G[i].clear();
18         color[i]=-1;
19     }
20     ans[0]=ans[1]=0;
21
22 }
23 void dfs(int cur,int cnt)
24 {
25     for(int i=0;i<G[cur].size();i++)
26     {
27         int u=G[cur][i];
28         if(color[u]==-1)
29         {
30             color[u]=0;
31             ans[cnt]++;
32             dfs(u,cnt^1);
33         }
34     }
35 }
36 int main()
37 {
38     int t;
39     scanf("%d",&t);
40     while(t--)
41     {
42         scanf("%d%d",&n,&m);
43         init();
44         for(int i=0;i<m;i++)
45         {
46             int x,y;
47             scanf("%d%d",&x,&y);
48             G[x].push_back(y);
49             G[y].push_back(x);
50         }
51         for(int i=1;i<=n;i++)
52         {
53             if(color[i]==-1 && G[i].size()!=0)
54             {
55                 color[i]=0;
56                 ans[0]++;
57                 dfs(i,1);
58             }
59         }
60
61         int res=0;
62
63         for(int i=1;i<=n;i++)
64         {
65             if(color[i]==-1)
66               res++;
67         }
68
69         while(res--)
70         {
71             if(ans[0]<ans[1])
72               ans[0]++;
73              else
74                ans[1]++;
75         }
76         printf("%d\n",ans[0]*ans[1]-m);
77     }
78
79     return 0;
80 }

解法二:并查集

dis数组用来记录各个点的状态,即记录点是加入左边还是右边。其他的基本相同。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 using namespace std;
 5 #define N 10006
 6 int n,m;
 7 int vis[N];
 8 int fa[N];
 9 int dis[N];
10 void init()
11 {
12     for(int i=0;i<=n;i++)
13     {
14         fa[i]=i;
15         vis[i]=dis[i]=0;
16     }
17 }
18 int find(int x)
19 {
20     if(x!=fa[x])
21     {
22         int t=find(fa[x]);
23         dis[x]=(dis[x]+dis[fa[x]])&1;
24         fa[x]=t;
25     }
26     return fa[x];
27 }
28 void merge(int x,int y)
29 {
30     int root1=find(x);
31     int root2=find(y);
32     if(root1==root2) return;
33     fa[root1]=root2;
34     dis[root1]=(dis[x]+dis[y]+1)&1;
35 }
36 int main()
37 {
38     int t;
39     scanf("%d",&t);
40     while(t--)
41     {
42         scanf("%d%d",&n,&m);
43         init();
44         for(int i=0;i<m;i++)
45         {
46             int x,y;
47             scanf("%d%d",&x,&y);
48             merge(x,y);
49             vis[x]=vis[y]=1;
50         }
51
52         //int cnt=x=y=0;
53         int cnt=0;
54         int x=0;
55         int y=0;
56         for(int i=1;i<=n;i++)
57           find(i);
58           for(int i=1;i<=n;i++)
59           {
60               if(vis[i]) if(dis[i]&1) x++; else y++;
61               else cnt++;
62           }
63           while(cnt--)
64           {
65               if(x<y)
66                 x++;
67                  else
68                    y++;
69           }
70           printf("%d\n",x*y-m);
71
72     }
73     return 0;
74 }

时间: 2024-11-05 14:41:11

hdu 5313 Bipartite Graph(dfs染色 或者 并查集)的相关文章

hdu 5313 Bipartite Graph(dfs+背包)

题意:n个点m条边,每条边的两个端点已知,求构成完全二分图能加的最多的边数: 参考:http://blog.csdn.net/acmhonor/article/details/47072399 思路:并不是一个二分图的题... n个点构成完全二分图是,两边的点数差值最小时边数最多(X+Y=n,求max(x*y)): 即在给定一些边的情况下,要求的是将点分在两个集合中数量差最小的情况: 先求出每个联通块中的点的情况,考虑孤立点的个数,通过贪心实现剪枝: 非贪心的情况使用背包,背包容量为n/2,推出

HDU 5313 Bipartite Graph(二分图染色+01背包水过)

Problem Description Soda has a bipartite graph with n vertices and m undirected edges. Now he wants to make the graph become a complete bipartite graph with most edges by adding some extra edges. Soda needs you to tell him the maximum number of edges

hdu 5313 Bipartite Graph 完全二分图 深搜 bitset应用

Bipartite Graph Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 577    Accepted Submission(s): 154 Problem Description Soda has a bipartite graph with n vertices and m undirected edges. Now he

HDU 5313——Bipartite Graph——————【二分图+dp+bitset优化】

Bipartite Graph Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 840    Accepted Submission(s): 285 Problem Description Soda has a bipartite graph with n vertices and m undirected edges. Now he w

HDU 5313 Bipartite Graph

题意:给一个二分图,问想让二分图变成完全二分图最多能加多少条边. 解法:图染色+dp+bitset优化.设最终的完全二分图两部分点集为A和B,A中点个数为x,B中点个数为y,边数则为x × y,答案即为x × y - m,那么用dp计算集合A中点个数的可能性.先用图染色计算每个连通分量里两种颜色点的个数,用dp[i][j]表示加入第i个连通分量时A集合中有j个点的可能性,可能为1,不可能为0,设联通分量为p,可以得到转移方程为dp[i][j] = dp[i - 1][j - p[i][0]] |

HDU 5313 Bipartite Graph (二分图着色,dp) TLE!!!

题意:Soda有一个$n$个点$m$条边的二分图, 他想要通过加边使得这张图变成一个边数最多的完全二分图. 于是他想要知道他最多能够新加多少条边. 注意重边是不允许的. 思路:二分图着色这个简单,主要是dp,还有时间限制.我觉得应该是找出所有连通分量,每个连通分量两边的点数存起来,后面统一进行DP.但是!!时间仅有1s,而且还100个例子,就是说大概要在100万的复杂度才行,可是有1万个点,当m=5000时,这就不行. 我不懂这道题如何下手才能保证一定正确且不超时,应该优化得很厉害~ 贴一个我认

hdu 1198 Farm Irrigation (搜索或并查集)

Farm Irrigation Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 5818    Accepted Submission(s): 2521 Problem Description Benny has a spacious farm land to irrigate. The farm land is a rectangle

hdu 1829 A Bug&#39;s Life (基础并查集)

题目: 链接:点击打开链接 题意: 给定虫子的交配关系,确定实验是否支持教授的假设即没有同性恋或者不符合假设. 思路: 是一道基础的并查集题目.存在两个集合异性和同性,给出多组关系,看这两个集合有木有联系,即是否有同性恋. 定义一个数组sex[],sex[i]表示与编号i的性别相反的虫子编号.然后将和i虫子有联系的合并为同一个集合(认为是同性的).如果findset(u) == findset(v),出现了反常行为. 代码: #include <iostream> #include <c

HDU 1829 A Bug&#39;s Life (并查集)

题目链接:请戳这里. 题目大意及思路:给定n个Bugs(shen me gui)和m对Bugs之间的关系,假定关系是两个Bugs的男女关系,那么问存不存在同性恋的情况. 那么若a与b是男女关系,b与c是男女关系,那么a和c的性别我们就可以认为是相同的.我们用可以建立两个并查集,一类放男男关系,一类放女女关系. 那么若男男关系中出现了环的情况(即有共同的根),那么同性恋关系就出现了. #include<iostream> #include<cstdio> #include<cs