HDU 5313 Bipartite Graph (二分图着色,dp)
题意:
Soda有一个n个点m条边的二分图, 他想要通过加边使得这张图变成一个边数最多的完全二分图. 于是他想要知道他最多能够新加多少条边. 注意重边是不允许的.
思路:
先将二分图着色,将每个连通分量区分出左右两边的点,在着色过程中,顺便将每个连通分量两边的点数存起来,注意一个连通分量左右两边的点数是绑定的一对数字。现在的问题就是,需要将这几对数字给分配掉,每一对都必须拆开来丢到不同的桶中,而且尽量使得两桶中各自的数字之和最接近,才能使得边最多。
分配的过程可以使用DP解决,主要是数字挺大的,bitset优化的背包很强大,可以解决这个问题。
bitset优化了的代码:
#include <bits/stdc++.h>
#define LL long long
#define pii pair<int,int>
#define INF 0x7f7f7f7f
using namespace std;
const int N=;
vector<int> vect[N];
int col[N], set1, set2; void color(int u, int c)
{
col[u]=c;
col[u]==?set2++:set1++;//统计两边的数量
for(int i=; i<vect[u].size(); i++)
{
int t=vect[u][i];
if(!col[t]) color(t, -col[u] );
}
} bitset<N> dp;
int s1[N/], s2[N/];
int cal(int n, int m)
{
if(m==n/*(n-n/) ) return ;
dp.reset(); memset(col, , sizeof(col));
int ans=, k=;
for(int i=; i<=n; i++)
{
if(!col[i])
{
set1=set2=;
color(i, ); s1[k]=set1;//每个连通分量两边的点数
s2[k++]=set2;
}
} dp[]=;
for(int i=; i<k; i++) //类似于背包+bitset优化
dp = dp<<s1[i] | dp<<s2[i]; //这么神奇!! for(int i=n/; i>=; i--) //再将那个最接近n/2的找出来即可
if( dp[i] ) return i*(n-i)-m;
} int main()
{
freopen("input.txt", "r", stdin);
int n, m, t, p, q, a, b;
cin>>t; while(t--)
{
scanf("%d%d",&n,&m);
for(int i=; i<=n; i++) vect[i].clear();
for(int i=; i<m; i++)
{
scanf("%d%d",&a,&b);
vect[a].push_back(b);
vect[b].push_back(a);
}
printf("%d\n",cal(n, m));
}
return ;
}
AC代码
贴一个没有优化的TLE代码:
#include <bits/stdc++.h>
#define LL long long
#define pii pair<int,int>
#define INF 0x7f7f7f7f
using namespace std;
const int N=;
vector<int> vect[N];
int col[N];
int set1, set2; void color(int u, int c)
{
col[u]=c;
if(col[u]==) set1++;//统计两边的数量
else set2++; for(int i=; i<vect[u].size(); i++)
{
int t=vect[u][i];
if(!col[t]) //没色
color(t, -col[u] );
}
} bitset<N/> dp[N];
int s1[N/],s2[N/];
int cal(int n, int m)
{
if(m==n/*(n-n/) ) return ;
for(int i=; i<=n; i++) vect[i].clear(), dp[i].reset(); memset(col, , sizeof(col));
int ans=, k=;
for(int i=; i<=n; i++)
{
if(!col[i])
{
set1=set2=;
color(i, ); s1[k]=set1;//每个连通分量两边的点数
s2[k++]=set2;
}
} if(k==) return s1[] * s2[] - m;//连通图
dp[][]=;
for(int i=; i<k; i++)//在这进行DP,尽量使得两边的点数平衡
{
ans=;
set1=s1[i];
set2=s2[i]; for(int j=n/; j>=set1; j--)
if( dp[i][j-set1] ) dp[i+][j]=,ans=max(ans,j); for(int j=n/; j>=set2; j--)
if( dp[i][j-set2] ) dp[i+][j]=,ans=max(ans,j);
}
return ans*(n-ans)-m;
} int main()
{
//freopen("input.txt", "r", stdin);
int n, m, t, p, q, a, b;
cin>>t; while(t--)
{
scanf("%d%d",&n,&m);
for(int i=; i<m; i++)
{
scanf("%d%d",&a,&b);
vect[a].push_back(b);
vect[b].push_back(a);
}
printf("%d\n",cal(n, m));
}
return ;
}
TLE代码
HDU 5313 Bipartite Graph (二分图着色,dp)的更多相关文章
- HDU 5313——Bipartite Graph——————【二分图+dp+bitset优化】
Bipartite Graph Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)T ...
- HDU 5313 Bipartite Graph(二分图染色+01背包水过)
Problem Description Soda has a bipartite graph with n vertices and m undirected edges. Now he wants ...
- hdu 5313 Bipartite Graph(dfs染色 或者 并查集)
Problem Description Soda has a bipartite graph with n vertices and m undirected edges. Now he wants ...
- HDU 5313 Bipartite Graph
题意:给一个二分图,问想让二分图变成完全二分图最多能加多少条边. 解法:图染色+dp+bitset优化.设最终的完全二分图两部分点集为A和B,A中点个数为x,B中点个数为y,边数则为x × y,答案即 ...
- bzoj 5006(洛谷 4547) [THUWC2017]Bipartite 随机二分图——期望DP
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=5006 https://www.luogu.org/problemnew/show/P4547 ...
- 2015多校第6场 HDU 5354 Bipartite Graph CDQ,并查集
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5354 题意:求删去每个点后图是否存在奇环(n,m<=1e5) 解法:很经典的套路,和这题一样:h ...
- 二分图点染色 BestCoder 1st Anniversary($) 1004 Bipartite Graph
题目传送门 /* 二分图点染色:这题就是将点分成两个集合就可以了,点染色用dfs做, 剩下的点放到点少的集合里去 官方解答:首先二分图可以分成两类点X和Y, 完全二分图的边数就是|X|*|Y|.我们的 ...
- HDU 5285 wyh2000 and pupil (二分图着色)
题意: 共有n个小学生,编号为1−n.将所有小学生分成2组,每组都至少有1个人.但是有些小学生之间并不认识,而且如果a不认识b,那么b也不认识a.Wyh2000希望每组中的小学生都互相认识.而且第一组 ...
- HDU 6321 Dynamic Graph Matching
HDU 6321 Dynamic Graph Matching (状压DP) Problem C. Dynamic Graph Matching Time Limit: 8000/4000 MS (J ...
随机推荐
- 2012 Asia Hangzhou Regional Contest
Friend Chains http://acm.hdu.edu.cn/showproblem.php?pid=4460 图的最远两点距离,任意选个点bfs,如果有不能到的点直接-1.然后对于所有距离 ...
- XEE介绍
摘要: XMl Entity Expansion(攻击)某种程度上类似于 XML Entity Expansion,但是它主要试图通过消耗目标程序的服务器环境来进行DOS攻击的.这种攻击基于XML E ...
- .net RESX资源文件
RESX资源文件最大的优势就是: 支持多语言 快速创建资源 管理方便 RESX可以支持多语言,Visual Studio编译后会出现附属程序集(satellite assembly),事实上是连接器( ...
- hadoop+hbase
hadoop的配置见下面这篇文章 http://www.powerxing.com/install-hadoop-2-4-1-single-node/ Hadoop安装教程_单机/伪分布式配置_Had ...
- 【QT】计时器制作
应小伙伴的要求,做一个小计时器.功能是点击开始就从00:00:00开始计时,点击暂停就暂停计时,点击停止就停止计时. 界面如上图,使用ui设计师直接拖的.按钮和图标的图片都是网上下载的.用美图秀秀抠成 ...
- crontab定时运行git命令 更新代码库
Q: http://stackoverflow.com/questions/7994663/git-push-via-cron I'm trying to run a git push fro ...
- hdu 4315 Climbing the Hill 博弈论
题意:有n个人爬山,山顶坐标为0,其他人按升序给出,不同的坐标只能容纳一个人(山顶不限),Alice和Bob轮流选择一个人让他移动任意步,但不能越过前面的人,且不能和前面一个人在相同的位置.现在有一个 ...
- mysql的学习记录
1 MySQL -h localhost -u UserName -p Password-h不写,默认为localhost注意:最好先MySQL -h localhost -u UserName -p ...
- 【PHPsocket编程专题(实战篇③)】构建基于socket的HTTP请求类
该代码是两年前写的,现在看起来有点渣了,仅仅是提供一个思路,现在做一些Api开发的时候官方会有一些SDK,这些SDK其实原理都是通过socket来通讯的,其实我个人主张用curl更方便,当然前提是你的 ...
- 【Linux高频命令专题(10)】mv
概述 mv命令是move的缩写,可以用来移动文件或者将文件改名(move (rename) files),是Linux系统下常用的命令,经常用来备份文件或者目录. 命令格式 mv [选项] 源文件或目 ...