BZOJ 3546 [ONTAK2010]Life of the Party (二分图最大匹配必须点)
题解:给出一个二分图,问你取点哪个点会使得二分图匹配数减少。
解法:其实就是问二分图匹配的必须点。先对初始二分图做一次最大匹配。
现在考虑左边点,看残余网络上的边重新构图:如果是匹配边那么就从右往左连边,如果是非匹配边就从左往右连边。然后从每个非匹配点出发dfs标记每一个访问过的点。最后是匹配点且未被访问过的就是必须点。为什么呢?仔细考虑新构的图,从未匹配点出发的其实也是一条增广路,如果这条增广路能访问到 已匹配点 。那么我们就可以把这条增广路取反得到另一种匹配方案,也就是说这个被访问到的 已匹配点是非必须的。
右边点原理相似。
细节详见代码以及注释:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
const int N=+;
const int M=+;
const int INF=0x3f3f3f3f;
int n1,n2,m,s,t,id[M<<];
struct edge{
int nxt,to,cap;
}edges[M<<];
int cnt=,x[M],y[M],head[N],cur[N]; int add_edge(int x,int y,int z) {
edges[++cnt].nxt=head[x]; edges[cnt].to=y; edges[cnt].cap=z; head[x]=cnt;
return cnt;
} int dep[N];
queue<int> q;
bool bfs() {
while (!q.empty()) q.pop();
memset(dep,,sizeof(dep));
dep[s]=; q.push(s);
while (!q.empty()) {
int x=q.front(); q.pop();
for (int i=head[x];i;i=edges[i].nxt) {
edge e=edges[i];
if (!dep[e.to] && e.cap) {
dep[e.to]=dep[x]+;
q.push(e.to);
}
}
}
return dep[t];
} int dfs(int x,int lim) {
if (x==t) return lim;
for (int& i=cur[x];i;i=edges[i].nxt) {
edge e=edges[i];
if (dep[x]+==dep[e.to] && e.cap) {
int flow=dfs(e.to,min(lim,e.cap));
if (flow>) {
edges[i].cap-=flow;
edges[i^].cap=+flow;
return flow; //找到一条增广路就要return
}
}
}
return ;
} int Dinic() {
int maxflow=;
while (bfs()) {
for (int i=s;i<=t;i++) cur[i]=head[i]; //当前弧优化
while (int flow=dfs(s,INF)) maxflow+=flow;
}
return maxflow;
} bool vis[N],match[N]; vector<int> G[N];
bool dfs2(int x) {
vis[x]=;
for (int i=;i<G[x].size();i++) {
int y=G[x][i];
if (!vis[y]) dfs2(y);
}
} int main()
{
scanf("%d%d%d",&n1,&n2,&m);
s=; t=n1+n2+;
for (int i=;i<=m;i++) {
scanf("%d%d",&x[i],&y[i]);
id[i]=add_edge(x[i],y[i]+n1,);
add_edge(y[i]+n1,x[i],);
}
for (int i=;i<=n1;i++) add_edge(s,i,),add_edge(i,s,);
for (int i=;i<=n2;i++) add_edge(n1+i,t,),add_edge(t,n1+i,); Dinic(); //重新构图
for (int i=;i<=n1+n2;i++) vis[i]=,match[i]=,G[i].clear();
for (int i=;i<=m;i++)
if (edges[id[i]].cap) G[x[i]].push_back(n1+y[i]); //不匹配边左到右连边
else G[n1+y[i]].push_back(x[i]),match[x[i]]=; //匹配边右到左连边
for (int i=;i<=n1;i++) if (!match[i]) dfs2(i); //从每个未匹配点出发dfs
for (int i=;i<=n1;i++)
if (match[i] && !vis[i]) printf("%d\n",i); //是匹配点且未被 未匹配点 访问的 for (int i=;i<=n1+n2;i++) vis[i]=,match[i]=,G[i].clear();
for (int i=;i<=m;i++)
if (edges[id[i]].cap) G[n1+y[i]].push_back(x[i]); //不匹配边右到左连边
else G[x[i]].push_back(n1+y[i]),match[n1+y[i]]=; //匹配边左到右连边
for (int i=;i<=n2;i++) if (!match[n1+i]) dfs2(n1+i); //从每个未匹配点出发dfs
for (int i=;i<=n2;i++)
if (match[n1+i] && !vis[n1+i]) printf("%d\n",i); //是匹配点且未被 未匹配点 访问的
return ;
}
BZOJ 3546 [ONTAK2010]Life of the Party (二分图最大匹配必须点)的更多相关文章
- BZOJ.3546.[ONTAK2010]Life of the Party(二分图匹配 ISAP)
题目链接 题意:求哪些点一定在最大匹配中. 这儿写过,再写一遍吧. 求哪些点不一定在最大匹配中.首先求一遍最大匹配,未匹配点当然不一定在最大匹配中. 设一个未匹配点为A,如果存在边A-B,且存在匹配边 ...
- bzoj 1854: [Scoi2010]游戏 (并查集||二分图最大匹配)
链接: https://www.lydsy.com/JudgeOnline/problem.php?id=1854 写法1: 二分图最大匹配 思路: 将武器的属性对武器编号建边,因为只有10000种 ...
- BZOJ 3546 Life of the Party (二分图匹配-最大流)
题目链接:http://www.lydsy.com:808/JudgeOnline/problem.php?id=3546 题意:给定一个二分图.(AB两个集合的点为n,m),边有K个.问去掉哪些点后 ...
- 【刷题】BZOJ 3546 [ONTAK2010]Life of the Party
Description 一个舞会有N个男孩(编号为1..N)和M个女孩(编号为1..M),一对男女能够组成一对跳舞当且仅当他们两个人互相认识. 我们把一种人定义成这个舞会的life:当且仅当如果他(她 ...
- [bzoj 1059][ZJOI 2007]矩阵游戏(二分图最大匹配)
题目:http://www.lydsy.com/JudgeOnline/problem.php?id=1059 分析:不论如何交换,同一行或同一列的点还是同一行或同一列,如果我们称最后可以排成题目要求 ...
- BZOJ 4443: [Scoi2015]小凸玩矩阵 二分图最大匹配+二分
题目链接: http://www.lydsy.com/JudgeOnline/problem.php?id=4443 题解: 二分答案,判断最大匹配是否>=n-k+1: #include< ...
- BZOJ 3993: [SDOI2015]星际战争 [二分答案 二分图]
3993: [SDOI2015]星际战争 题意:略 R1D2T1考了裸二分答案+二分图最大匹配... #include <iostream> #include <cstdio> ...
- [bzoj 1143]最长反链二分图最大匹配
Dilworth定理:偏序集能划分成的最少的全序集的个数与最大反链的元素个数相等. 证明:http://www.cnblogs.com/itlqs/p/6636222.html 题目让求的是最大反链的 ...
- POJ 2226二分图最大匹配
匈牙利算法是由匈牙利数学家Edmonds于1965年提出,因而得名.匈牙利算法是基于Hall定理中充分性证明的思想,它是二部图匹配最常见的算法,该算法的核心就是寻找增广路径,它是一种用增广路径求二分图 ...
随机推荐
- Tkinter初体验
一.基本步骤 1.导入Tkinter模块 2.创建根窗口 3.填充组件 4.组件关联逻辑 5.进入主循环 二.Code #coding:utf-8 ''' 网关流量校验器 @author: Hongz ...
- 九、结构模式之装饰(Decorator)模式
装饰模式又叫包装模式,装饰模式以客户端透明的方式扩展对象的功能,是继承关系的一个替代方案.装饰模式可以在不使用创造更多的子类的情况下,将对象的功能加以扩展. 装饰模式结构图如下: 其包含的角色就分为: ...
- Spring Bean 的加载过程
Spring Bean 的加载过程 一个是populateBean,一个是initializeBean,这两个方法完成了bean的赋值与初始化. 这里有一个BeanDefinitionValueRes ...
- ThreadLocal简单使用示例
ThreadLocal为每个线程提供单独的数据副本,线程间的数据为自身线程所独有(不存在共享变量问题),直接看代码 public class ThreadLocalTest { private sta ...
- 解决分布式事务基本思想Base和CPA理论、最终一致性|刚性事务、柔性事务
在学习解决分布式事务基本思路之前,大家要熟悉一些基本解决分布式事务概念名词比如:CAP与Base理论.柔性事务与刚性事务.理解最终一致性思想,JTA+XA.两阶段与三阶段提交等. 如何保证强一致性呢? ...
- InnoDB的LRU淘汰策略
Reference: https://time.geekbang.org/column/article/121710 InnoDB存储引擎是基于集合索引实现的数据存储,也就是除了索引列以及主键是存储在 ...
- zookeeper问题排查
一.无法启动 zookeeper之前可以很好的运行,由于zk集群不是正常的关闭,比如 强制Linux关闭,直接执行kill 命令zk的进程等原因导致zookeeper启动不了 启动命令后,查看状态,会 ...
- 【leetcode】756. Pyramid Transition Matrix
题目如下: We are stacking blocks to form a pyramid. Each block has a color which is a one letter string, ...
- 【NOIP2019模拟2019.11.13】旅行 && GDKOI2018 还念(二分答案+dij)
Description: 题解: 显然满足二分性. 并且每一条边要不选l要不选r. 二分的那条链肯定要选l. 考虑有两个人在走最短路,一个人一开始必须走二分的那条链,要求第一个人走的比第二个人快. 安 ...
- QByteArray和十六进制的QString(char*)相互转换
#include <QCoreApplication> #include <QDebug> #include <QDataStream> QByteArray He ...