LOJ2276 [HAOI2017] 新型城市化 【二分图匹配】【tarjan】
题目分析:
这题出的好!
首先问题肯定是二分图的最大独立集,如果删去某条匹配边之后独立集是否会变大。
跑出最大流之后流满的边就是匹配边。
如果一个匹配边的两个端点在一个强连通分量里,那这条边删掉之后我们就可以找到一个替代方案使得匹配不变小。
具体的,假设这两个点是x,y。因为两者之间连的是匹配边,那么存在一个路径从t->y->x->s。那只要从s有另一条路径到y或者从x有另一条路径到t那就构成一个强连通分量,我们只考虑s到y的情况。
如果存在一条这样的路,我们会发现每次从X集合跳到Y集合的时候走的是黑边,从Y集合跳到X集合的时候走的是红遍,因为我们的目标节点在Y集合,所以采用匈牙利树的分析方法,黑边总比红边多1,所以可以把这条路径翻转达到我们的目的。
代码:
#include<bits/stdc++.h>
using namespace std; const int maxm = ,maxn = ; struct edge{int from,to,flow;}edges[maxm];
int num,n,m,arr[maxn];
vector <int> g[maxn];
int color[maxn]; namespace BioGraph{
vector<int> T[maxn];
queue<int> Q;
void pd(){
for(int i=;i<=n;i++){
if(arr[i]) continue;
Q.push(i); arr[i] = ; color[i] = ;
while(!Q.empty()){
int k = Q.front(); Q.pop();
for(int i=;i<T[k].size();i++){
int z = T[k][i];
if(arr[z]) continue;
Q.push(z); color[z] = (color[k]^); arr[z] = ;
}
}
}
}
}
namespace SCC{
int dfn[maxn],low[maxn],scc[maxn],sccnum,cl;
stack<int> sta;
void Tarjan(int now){
low[now] = dfn[now] = ++cl;
sta.push(now);
for(int i=;i<g[now].size();i++){
if(edges[g[now][i]].flow == ) continue;
int to = edges[g[now][i]].to;
if(arr[to]) continue;
if(dfn[to]) low[now] = min(low[now],dfn[to]);
else{Tarjan(to);low[now] = min(low[now],low[to]);}
}
if(low[now]==dfn[now]){
sccnum++;
while(true){
int pi = sta.top(); sta.pop();
arr[pi] = ; scc[pi] = sccnum;
if(now == pi) break;
}
}
}
} void AddEdge(int x,int y,int v){
edges[num++] = (edge){x,y,v};
edges[num++] = (edge){y,x,};
g[x].push_back(num-);
g[y].push_back(num-);
} int dis[maxn],cur[maxn];
queue<int> qq;
int BFS(){
qq.push(); memset(dis,-,sizeof(dis)); dis[] = ;
while(!qq.empty()){
int k = qq.front(); qq.pop();
for(int i=;i<g[k].size();i++){
edge sm = edges[g[k][i]];
if(sm.flow && dis[sm.to]== -){
dis[sm.to] = dis[k]+;
qq.push(sm.to);
}
}
}
return dis[n+];
} int dfs(int x,int a){
if(x == n+ || a == ) return a;
int flow = ,f;
for(int &i=cur[x];i<g[x].size();i++){
edge &xx = edges[g[x][i]];
if(dis[xx.to]>dis[x]&&(f=dfs(xx.to,min(a,xx.flow)))){
xx.flow -= f;
flow += f;
a -= f;
edges[g[x][i]^].flow+=f;
if(a == ) return flow;
}
}
return flow;
} void read(){
scanf("%d%d",&n,&m);
for(int i=;i<=m;i++){
int x,y; scanf("%d%d",&x,&y);
BioGraph::T[x].push_back(y);
BioGraph::T[y].push_back(x);
}
BioGraph::pd();
for(int i=;i<=n;i++){
if(color[i]) {AddEdge(i,n+,);continue;}
else AddEdge(,i,);
for(int j=;j<BioGraph::T[i].size();j++){
int z = BioGraph::T[i][j];
AddEdge(i,z,);
}
}
} vector<pair<int,int> > res;
void work(){
int flow = ;
while(BFS() != -){
memset(cur,,sizeof(cur));
flow += dfs(,);
}
memset(arr,,sizeof(arr));
for(int i=;i<=n+;i++){
if(arr[i]) continue;
SCC::Tarjan(i);
}
for(int i=;i<num;i++){
if(edges[i].from == || edges[i].to == n+) continue;
if(edges[i].from == n+ || edges[i].to == ) continue;
if(color[edges[i].from]) continue;
if(edges[i].flow) continue;
if(SCC::scc[edges[i].from] == SCC::scc[edges[i].to]) continue;
int x=min(edges[i].from,edges[i].to),y=max(edges[i].from,edges[i].to);
res.push_back(make_pair(x,y));
}
sort(res.begin(),res.end());
int z = res.size(); printf("%d\n",z);
for(int i=;i<z;i++){ printf("%d %d\n",res[i].first,res[i].second); }
} int main(){
read();
work();
return ;
}
LOJ2276 [HAOI2017] 新型城市化 【二分图匹配】【tarjan】的更多相关文章
- HAOI2017 新型城市化 二分图的最大独立集+最大流+强连通缩点
题目链接(洛谷):https://www.luogu.org/problemnew/show/P3731 题意概述:给出一张二分图,询问删掉哪些边之后可以使这张二分图的最大独立集变大.N<=10 ...
- 【Luogu3731】[HAOI2017]新型城市化(网络流,Tarjan)
[Luogu3731][HAOI2017]新型城市化(网络流,Tarjan) 题面 洛谷 给定一张反图,保证原图能分成不超过两个团,问有多少种加上一条边的方法,使得最大团的个数至少加上\(1\). 题 ...
- 求去掉一条边使最小割变小 HAOI2017 新型城市化
先求最小割,然后对残量网络跑Tarjan.对于所有满流的边,若其两端点不在同一个SCC中,则这条边是满足条件的. 证明见 来源:HAOI2017 新型城市化
- HDU4685:Prince and Princess(二分图匹配+tarjan)
Prince and Princess Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 65535/32768 K (Java/Othe ...
- 洛谷 P3731 [HAOI2017]新型城市化【最大流(二分图匹配)+tarjan】
我到底怎么建的图为啥要开这么大的数组啊?! 神题神题,本来以为图论出不出什么花来了. 首先要理解'团'的概念,简单来说就是无向图的一个完全子图,相关概念详见度娘. 所以关于团一般都是NP问题,只有二分 ...
- Luogu3731 HAOI2017新型城市化(二分图匹配+强连通分量)
将未建立贸易关系看成连一条边,那么这显然是个二分图.最大城市群即最大独立集,也即n-最大匹配.现在要求的就是删哪些边会使最大匹配减少,也即求哪些边一定在最大匹配中. 首先范围有点大,当然是跑个dini ...
- P3731 [HAOI2017]新型城市化(tarjan+网络流)
洛谷 题意: 给出两个最大团的补图,现在要求增加一条边,使得最大最大团个数增加至少\(1\). 思路: 我们求出团的补图,问题可以转换为:对于一个二分图,选择删掉一条边,能够增大其最大独立集的点集数. ...
- Luogu P3731 [HAOI2017]新型城市化
题目显然可以转化为求每一条边对二分图最大独立集的贡献,二分图最大独立集\(=\)点数\(-\)最大匹配数,我们就有了\(50pts\)做法. 正解的做法是在原图上跑\(Tarjan\),最开始我想复杂 ...
- HDU 4685 Prince and Princess 二分图匹配+tarjan
Prince and Princess 题目连接: http://acm.hdu.edu.cn/showproblem.php?pid=4685 Description There are n pri ...
随机推荐
- 对于jQuery的了解
1.了解jQuery与JavaScript的区别 css --外貌特征Html --躯干,骨架js --运动神经 jQuery就是对JavaScript的一个拓展,封装,就是让JavaScript更好 ...
- 都 9012了,该选择 Angular、React,还是Vue?
转载请注明出处:葡萄城官网,葡萄城为开发者提供专业的开发工具.解决方案和服务,赋能开发者. 尽管 Web开发的典型应用场景除了将服务器用作平台.浏览器用作客户端之外,几乎很少活跃于其他业务领域,但不可 ...
- [置顶]生鲜配送管理系统_升鲜宝V2.0 销售订单汇总_采购任务分配功能_操作说明
做好生鲜供应链系统,要注意三个方面,1.分拣 2 采购 3 库存,市面上做的比较成熟的功能,还是分拣这一块(按客户分拣.按订单分拣.按商品分类分拣.按商品分拣.按线路分拣.客户自由组合分拣)[下篇文 ...
- Linux通过NFS实现文件共享
在项目生产环境我们经常需要实现文件共享,传统的常见方案是通过NFS,实现服务器之间共享某一块磁盘,通过网络传输将分散的文件集中存储在一块指定的共享磁盘,实现基本的文件共享.实现这种方案,分服务端和客户 ...
- vcenter 忘记 administrator@vsphere.local 密码怎么办
现有一个windows版本的vcenter5.5管理员密码丢失,我们可以使用vmware的工具vdcadmintool,在命令行进入到vdcadmintool所在的目录,然后执行下vdcadminto ...
- Docker:pipeline编写基本技巧- jenkins配置通过免交互方式拉取git源码管理仓库的代码
工作中,从git仓库拉取代码有2种方式:交互式和非交互式 什么是交互式?就是拉取需要权限才能访问的代码时,需要输入密码 免交互式呢? 是通过密钥,私钥的方式,让服务端信任客户端,产生信任后,任何一次客 ...
- 【Teradata SQL】日历函数查询
查询2018年agmt_id=1076226890174464676612的,且金额类型代码为0212,每日协议金额. 1.协议金额历史表取某一日数据(20180101) sel t.start_dt ...
- C/C++中容器vector用法
C++中数组非常坑,有没有相似Python中list的数据类型呢?相似的就是vector!vector 是同一种类型的对象的集合,每一个对象都有一个对应的整数索引值. 和 string 对象一样.标准 ...
- python学习——读取染色体长度(一、简化问题)
# 读取fasta # 解析每条序列的长度 chr1_len = 10 chr2_len = 20 chr3_len = 30 chr4_len = 40 chr5_len = 50 # 求和 tot ...
- 在 .NET Core 中运行 JavaScript
一.前言 在 .NET Framework 时,我们可以通过V8.NET等组件来运行 JavaScript,不过目前我看了好几个开源组件包括V8.NET都还不支持 .NET Core ,我们如何在 . ...