二分图匹配(二)

文章目录

  • 例题:
    • NC20483 [ZJOI2009]假期的宿舍
      • 题目描述:
      • 题解:
    • NC51316 Going Home
      • 题目描述:
      • 题解:
    • NC107638 poj3041 Asteroids
      • 题目描述:
      • 题解:
    • NC20472 [ZJOI2007]矩阵游戏
      • 题目描述:
      • 题解:
    • NC110335 CF387D George and Interesting Graph
      • 题目:
      • 题解:
      • 代码:
      • 代码:
    • NC131152 Gym 101873F Plug It In
      • 题意:
      • 题解:
      • 代 码:
    • NC112788 CF981F Round Marriage
      • 题目:
      • 题解:
      • 答案:

例题:

NC20483 [ZJOI2009]假期的宿舍

题目描述:

学校放假了 · · · · · · 有些同学回家了,而有些同学则有以前的好朋友来探访,那么住宿就是一个问题。比如 A 和 B 都是学校的学生,A 要回家,而 C 来看B,C 与 A 不认识。我们假设每个人只能睡和自己直接认识的人的床。那么一个解决方案就是 B 睡 A 的床而 C 睡 B 的床。
而实际情况可能非常复杂,有的人可能认识好多在校学生,在校学生之间也不一定都互相认识。我们已知一共有 n 个人,并且知道其中每个人是不是本校学生,也知道每个本校学生是否回家。
问是否存在一个方案使得所有不回家的本校学生和来看他们的其他人都有地方住。

题解:

构造二分图
一边是
本校学生有相应的床
一边是
要到学校的人
床与人构造边
在这里插入图片描述
• 左集合为所有需要床的人,右集合为所有的床
• 当第x个人可以睡第y张床(即认识第y个床的主人)那么就可以连边
• 求出最大匹配即可
详细题解+代码看

NC51316 Going Home

题目描述:

n 个小人回到 n 间房子,要求一对一,告诉每个人的位置和每个房子的位置,问n个人移动的总距离最少是多少

题解:

最小权值匹配模板
在这里插入图片描述
将所有值取相反数,然后跑一遍最优权值匹配模板

NC107638 poj3041 Asteroids

题目描述:

网格图中有若干个陨石,每次发射武器可以打掉某一行或某一列的所有陨石,求打完所有陨石的最少次数
在这里插入图片描述

题解:

首先,贪心的打星球最多的行/列有反例,如:
0 0 0 0
1 1 0 0
1 0 1 0
1 0 0 1
正解:
我们把行和列抽象为点,把陨石抽象为边,即当(x,y)有一个陨石的时候 ,将左边的第x个
点与右边的第y个点连边
• 最后是要找到最少的点(行/列)来覆盖掉所有的边(陨石)
• 也就是二分图的最小点覆盖!
最小点覆盖:在二分图中选尽量少的点覆盖所有的边
我们将问题转化为选左右最少数量的点可以覆盖所有边
而 最小点覆盖=最大匹配
在这里插入图片描述
比如例子:
0 0 0 0
1 1 0 0
1 0 1 0
1 0 0 1
在这里插入图片描述

NC20472 [ZJOI2007]矩阵游戏

题目描述:

• 小Q是一个非常聪明的孩子,除了国际象棋,他还很喜欢玩一个电脑益智游戏——矩阵游戏。
矩阵游戏在一个N *N黑白方阵进行(如同国际象棋一般,只是颜色是随意的)。
• 每次可以对该矩阵进行两种操作:
• 行交换操作:选择 矩阵的任意两行,交换这两行(即交换对应格子的颜色)
• 列交换操作:选择矩阵的任意行列,交换这两列(即交换 对应格子的颜色)
• 游戏的目标,即通过若干次操作,使得方阵的主对角线(左上角到右下角的连线)上的格子均为黑色。
• 对于某些关卡,小Q百思不得其解,以致他开始怀疑这些关卡是不是根本就是无解的!!于是小Q决定写一个程序来判断这些关卡是否有解。
• N<=200

题解:

问题可以转化成:
• 每一行只保留一个黑色的点,且让这些黑色的点所在的列各不相同(即覆盖到每一列)
• 把行列抽象成点,分别为左集合和右集合
• 把黑点抽象成边,连接对应的行和列
• 看最大匹配是不是等于n,如果等于n就可行

NC110335 CF387D George and Interesting Graph

题目:

给你一个无重边的有向图,你每次操作可以加一条边或者删一条边,求让图变成一个“有趣
图”的最小操作次数
• “有趣图”,满足:
• 存在一个中心结点v,它和其他每个点都有双向边,且和自身有自环。
• 除了中心结点之外,其他结点的入度和出度都为2。 • 2 ≤ n ≤ 500, 1 ≤ m ≤ 1000

题解:

题目要求的其他节点的入度和出度都为2,因为中心节点要与其他点都有一条边,去除中心节点 v之后(以及v所关联的边),剩下所有点组成环(一个或者多个不想交的环,因为环上的点入度出度都为1)
N不大,考虑枚举中心点u • 分类讨论:
• 和u有关的边:
• u的自环 ——没有就+1条,有就不管了
• u到每一个点的出边和入边——如果没有就加上这1条,如果有就不管

和u无关的边

将每个点的入度与出度分为左集合和右集合

• 当我们把和u有关的边都删掉以后,每个点的出度和入度都应该是1 • 在这种情况下我们要操作的次数最小,也就是保留尽量多的原来的边——把每个点拆成
入点和出点,所有的入点和出点分别为左集合和右集合,求出来的最大匹配就是能保留
的边,其他的边要删掉;而如果最大匹配数不等于非中心节点数,显然就还需要加边
(需要将二分图匹配加成满配才能满足每个点入度1出度1,这样原图也就变成了一个环或者多个不相交的环。)

代码:

目前为WA,没发现哪里错了。。。感觉应该没问题的

#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
inline int read(){int s=0,w=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();//s=(s<<3)+(s<<1)+(ch^48);return s*w;
}
const int maxn=600;
const int mod=500;
int g[maxn][maxn];
int a[1030][1030];
int tot=0;
int vis[maxn];
int link[maxn];
int n,m;
int maxmatch(int x)
{for(int i=1+n;i<=n+n;i++){if(a[x][i]==0||vis[i])continue;vis[i]=1;if(link[i]==0||maxmatch(link[i])){link[i]=x;return 1;}}return 0;
}
int main()
{cin>>n>>m;for(int i=1;i<=m;i++){int x,y;cin>>x>>y;g[x][y]=1;}int maxx=0x7f;for(int i=1;i<=n;i++){memset(link,0,sizeof(link));tot=0;if(g[i][i]!=1)tot++;for(int j=1;j<=n;j++){if(j==i)continue;if(g[i][j]==0)tot++;if(g[j][i]==0)tot++;}		int sum=0;int ans=0;for(int j=1;j<=n;j++){if(j==i)continue;for(int k=1;k<=n;k++){if(k==i)continue;if(g[j][k]){a[j][k+n]=1;a[k+n][j]=1;ans++;}}}//int op=0;for(int j=1;j<=n;j++){if(j==i)continue;memset(vis,0,sizeof(vis));sum+=maxmatch(j);}tot+=ans-sum;tot+=n-1-sum;maxx=min(maxx,tot);}cout<<maxx;
}

网上找的AC代码:

#include<stdio.h>
#include<string.h>
#include<iostream>
using namespace std;
int match[600];
int vis[600];
int a[600][600];
int x[4545];
int y[4545];
int n,m;
int find(int u)
{for(int i=1;i<=n;i++){if(a[u][i]==1&&vis[i]==0){vis[i]=1;if(match[i]==-1||find(match[i])){match[i]=u;return 1;}}}return 0;
}
int Slove(int u)
{int ans=0,tot=0;memset(a,0,sizeof(a));for(int i=1;i<=m;i++)a[x[i]][y[i]]=1;for(int i=1;i<=n;i++){for(int j=1;j<=n;j++){if(a[i][j]==1&&(i!=u)&&(j!=u))tot++;if(a[i][j]==0&&(i==u||j==u)){ans++;}if(i==u||j==u)a[i][j]=0;}}memset(match,-1,sizeof(match));int output=0;for(int i=1;i<=n;i++){memset(vis,0,sizeof(vis));if(i==u)continue;if(find(i))output++;}ans+=n-1-output;ans+=tot-output;return ans;
}
int main()
{while(~scanf("%d%d",&n,&m)){for(int i=1;i<=m;i++){scanf("%d%d",&x[i],&y[i]);}int ans=0x3f3f3f3f;for(int i=1;i<=n;i++){int tmp=Slove(i);ans=min(ans,tmp);}printf("%d\n",ans);}
}

代码:

NC131152 Gym 101873F Plug It In

评测地址

题意:

有m个插座,n个电器,每个插座最多可连接一个电器。另外有一个插线板,可以使得一个插座连接三个电器,给出每个插座能插的电器,问最多能插电器的个数是多少。
• N,m<=1500, k(边数)<=75000

题解:

先不考虑插线板 ——二分图最大匹配
• 插线板会使得某个插头被复制两份
• ——枚举插头然后加倍再跑最大匹配行不行?
• 会tle
• 因为插一个插头其实只是加了两个点——先把原图的最大匹配结果保留下来
• 然后每次在这个结果上加两个点,给它两找增广路即可。

代 码:

#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
inline int read(){int s=0,w=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();//s=(s<<3)+(s<<1)+(ch^48);return s*w;
}
const int maxn=1508;
int a[maxn][maxn];
int vis[maxn];
int link[maxn];
int link1[maxn];
int n,m,k;
int maxmatch(int x)
{for(int i=1;i<=m;i++){if(vis[i]||a[x][i]==0)continue;vis[i]=1;if(link[i]==0||maxmatch(link[i])){link[i]=x;return 1;}}return 0;
}
void init()
{for(int i=1;i<=m;i++){link[i]=link1[i];}
}
int main()
{cin>>n>>m>>k;//while(scanf("%d%d%d", &n, &m, &k) == 3){for(int i=1;i<=k;i++){int x,y;cin>>x>>y;a[x][y]=1;//a[y][x]=1;}int sum=0;for(int i=1;i<=n;i++){memset(vis,0,sizeof(vis));sum+=maxmatch(i);}//	cout<<"sum="<<sum<<endl;int maxx=0;for(int i=1;i<=m;i++){link1[i]=link[i];}for(int i=1;i<=n;i++){init();int tot=0;for(int j=1;j<=2;j++){memset(vis,0,sizeof(vis));tot+=maxmatch(i);}maxx=max(maxx,tot);//cout<<"tot="<<tot<<endl;//	cout<<"sum="<<sum<<endl;}cout<<sum+maxx<<endl;}}

NC112788 CF981F Round Marriage

题目:

• n个新郎和n个新娘围成一个环,环的长度为L,给出所有新郎可以站的位置和新娘可以站的位置,将新郎新娘安排到这些位置上,最 小化每一对新郎和新娘距离的最大值。
• 1≤n≤2*105 ,1 ≤ L≤ 109

题解:

• 二分答案
• 每次只添加男女之间不超过mid的边,求最大匹配
• 会tle
• Hall定理:对于一个二分图,如果对于左边任意子集S,其对应边连接了一个右边的点集T,
都有|S|≤|T|,那么这个二分图有完美匹配。(充要)
在这里插入图片描述
对于本题来说,左集合的点x,在右集合能匹配的点刚好是一个区间,记为[Lx,Rx] • 因为当x增大的时候,对应的区间也是右移的,所以我们只需要看连续的左集合——左集合中
任意区间[a,b]都需要满足其对应区间[La,Rb]中的元素比他多
• 即b-a<=Rb-La
• 移项: b-Rb<=a-La
sum[b]:b点及以前新郎个数
sum2[b]:b点及以前新娘个数
x是第几个新郎,Lx,Ly是新娘的范围
再枚举a,b

二分答案,判mid是否合法
如何判断:如果是在直线上,那么遍历匹配即可
现在在环上,即既可以向前匹配也可以向后匹配,那么将环拆开,扩展成三倍

显然a和b的匹配边是不可能交叉的,因为交叉必定没有不交叉优
hall定理:二分图两个点集A,B,连续一段A的点对应连续一段B的点的 充要条件是 这些点对的匹配边之间不交叉
重要推论:二部图G中的两部分顶点组成的集合分别为X,Y, 若|X|=|Y|,
且G中有一组无公共端点的边,一端恰好组成X中的点,一端恰好组成Y中的点,则称二部图G中存在完美匹配

有了这个定理,就可以用在判定上:a的点集对应b点集的连续一段,即b的n个点也是连续的,因为之前已经确定匹配边不交叉
先求出a[1]的范围[a[1]-mid,a[1]+mid]对应的能控制的b数组的范围[l1,r1]
那么a[2]的控制范围要和[l1+1,r1+1]交叉得到[l2,r2]
那么a[3]的控制范围要和[l2+1,r2+1]交叉得到[l3,r3]

…依次类推
可以这个区间长度只会减小不会变大

答案:

#include<bits/stdc++.h>
using namespace std;
#define maxn 200005
long long n,L,a[maxn],b[maxn<<2],c[maxn],m;int judge(int mid){//a[i]的控制区间是[a[i]-mid,a[i]+mid] int l=1,r=m;for(int i=1;i<=n;i++){while(a[i]-mid>b[l])++l;while(a[i]+mid<b[r])--r;if(l>r)return 0;++l,++r;} return 1;
}int main(){cin>>n>>L;for(int i=1;i<=n;i++)cin>>a[i];for(int i=1;i<=n;i++)cin>>c[i];sort(c+1,c+1+n);sort(a+1,a+1+n);for(int i=1;i<=n;i++)b[i]=c[i]-L;for(int i=1;i<=n;i++)b[i+n]=c[i];for(int i=1;i<=n;i++)b[i+2*n]=c[i]+L;m=3*n;int l=0,r=L,ans,mid;while(l<=r){mid=l+r>>1;if(judge(mid))ans=mid,r=mid-1;else l=mid+1;}cout<<ans<<'\n';
} 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/318534.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

质数和分解(动态规划)

文章目录题目描述解析记忆化搜索代码无限背包代码thanks for reading&#xff01;题目描述 解析 很好的题 记忆化搜索 我一开始的思路就是记忆化搜索 为了不重复&#xff0c;搜索的时候规定拆出来一个数A后一会不能再拆比A更小的了 这样就不难写了 &#xff08;忽略我n^2的素…

Graph Theory Class(Min25求1~n质数和)

Graph Theory Class 原理不会板子抄的。 // n^0.75/log 求1~n的质数和 #include <bits/stdc.h> #define ll long long using namespace std; const int N 10000010;ll n,mod; int prime[N],id1[N],id2[N],vis[N],cnt,m; ll g[N],s[N],a[N],T; int ID(ll x){return x<…

【.NET Core项目实战-统一认证平台】第十章 授权篇-客户端授权

上篇文章介绍了如何使用Dapper持久化IdentityServer4&#xff08;以下简称ids4&#xff09;的信息&#xff0c;并实现了sqlserver和mysql两种方式存储&#xff0c;本篇将介绍如何使用ids4进行客户端授权。.netcore项目实战交流群&#xff08;637326624&#xff09;&#xff0c;…

内存管理(ybtoj-二叉堆)

文章目录题目描述解析代码题目描述 解析 这题感觉做的不错 不难看出&#xff0c;要维护一个空闲的优先队列&#xff0c;在每次申请时弹出编号最小的 但是对判断当前哪些被访问的内存重新进入空闲状态是一个难题 最简单的办法是存起来每次扫一遍判断 但这样在极端数据时会TLE&…

P4233-射命丸文的笔记【NTT,多项式求逆】

正题 题目链接:https://www.luogu.com.cn/problem/P4233 题目大意 随机选择一条有哈密顿回路的nnn个点的竞赛图&#xff0c;求选出图的哈密顿回路的期望个数。 对于每个n∈[1,N]n\in[1,N]n∈[1,N]求答案。 1≤N≤1051\leq N\leq 10^51≤N≤105 解题思路 竟然自己推出来了泪…

HDU 5008 Boring String Problem ( 后缀数组求本质不同第k大子串)

Boring String Problem Zeronera题解 预处理sum数组记录不同字符串的个数&#xff0c;即sum[i] n- sa[i] 1 -height[i] sum[i-1] (n为原串长度) 对于每个k 若k > sum[n] 则输出0 0 &#xff0c;即k大于不同子串的总数 否则&#xff0c;二分sum数组找到第k小子串所在的…

HAPPY_TOGETHER_WEEK15_ENJOY

文章目录7-1 6翻了7-2 幸运彩票7-3 点赞7-4 猜数字7-5 出租7-6 A-B7-7 连续因子7-8 天梯赛座位分配7-9 大笨钟7-10 敲笨钟7-11 整除光棍7-1 6翻了 #include<iostream> #include<string> using namespace std; int main() {string str;int s;int count 0;getline(…

[翻译]初试C# 8.0

原文地址: https://blogs.msdn.microsoft.com/dotnet/2018/12/05/take-c-8-0-for-a-spin/初试C# 8.0昨天我们宣布了Visual Studio 2019的第一个预览版&#xff08;使用Visual Studio 2019提高每个开发人员的工作效率&#xff09;和.NET Core 3.0&#xff08;宣布.NET Core 3预览…

上帝造题的七分钟(ybtoj-树状数组)

文章目录题目描述解析代码thanks for reading&#xff01;题目描述 解析 差点活活恶心死 搬砖题 &#xff08;其实细节没有那么多&#xff0c;还是代码能力太差&#xff09; 利用矩阵的二维差分 加上树状数组搞一搞 就完事了&#xff08;我实在不想再写了 &#xff09; 洛谷…

ACM模板合集

目录数据结构STL以及基础数据结构并查集线段树树状数组平衡树树套树可并堆\sqrt{}​根号数据结构LCT字符串字符串匹配字符串其他数学数论线性代数组合数学网络流最大流最小割费用流图搜索最短路负环最短路建图最小生成树连通性相关欧拉路径二分图树上问题其他离线分治算法随机化…

P6657-[模板]LGV 引理

正题 题目链接:https://www.luogu.com.cn/problem/P6657 题目大意 给出nnn\times nnn的棋盘&#xff0c;mmm个起点第iii个为(1,ai)(1,a_i)(1,ai​)&#xff0c;对应mmm个终点第iii个为(n,bi)(n,b_i)(n,bi​)。 求有多少条选出mmm条四联通路径的方案使得没有路径有交点。 2≤…

STL初步讲解

文章目录sortmapvectorstackqueuepriority_queue初学C&#xff0c;发现经常在文件中有using namespace std这个东西。首先 namespace 这个东西叫做命名空间。using有好几种用法&#xff0c;这里使用的是using的命名空间的使用。 std是C中的一个命名空间&#xff0c;叫做标准命名…

.NET Core微服务之路:让我们对上一个Demo通讯进行修改,完成RPC通讯

最近一段时间有些事情耽搁了更新&#xff0c;抱歉各位了。上一篇我们简单的介绍了DotNetty通信框架&#xff0c;并简单的介绍了基于DotNetty实现了回路&#xff08;Echo&#xff09;通信过程。我们来回忆一下上一个项目的整个流程&#xff1a;当服务端启动后&#xff0c;绑定并…

洛谷:P1831 杠杆数(数位dp)

文章目录描述解析代码thanks for reading&#xff01;传送门描述 如果把一个数的某一位当成支点&#xff0c;且左边的数字到这个点的力矩和等于右边的数字到这个点的力矩和&#xff0c;那么这个数就可以被叫成杠杆数。 比如4139就是杠杆数&#xff0c;把3当成支点&#xff0c…

2021“MINIEYE杯”中国大学生算法设计超级联赛(7)部分题解

前言 找大佬嫖到个号来划水打比赛了&#xff0c;有的题没写或者不是我写的就不放了。 目前只有&#xff1a;1004,1005,1007,1008,1011 正题 题目链接:https://acm.hdu.edu.cn/contests/contest_show.php?cid990 1004 Link with Balls 题目大意 两种盒子各有nnn个&#xff…

Visual Studio 2019 首个预览版本抢先看,有啥新功能?

微软在 Connect 2018 大会上发布Visual Studio 2019 第 1 个预览版本。该预览版本中展示了许多变更&#xff0c;从 IDE 的启动行为&#xff0c;到代码重构功能&#xff1b;从搜索功能的更多用法&#xff0c;到更好的大型项目导航。这个预览版本展现了微软希望尽全力帮助开发人员…

模板:网络流(Dinic算法)

文章目录1.网络最大流题目描述解析反悔边分层&#xff08;避免环流&#xff09;时间优化代码2.费用流描述解析代码1.网络最大流 洛谷P3376 题目描述 给出一个网络图&#xff0c;以及其源点和汇点&#xff0c;求出其网络最大流。 解析 网络流的思想就是在原有的基础上不断进…

NC51272 棋盘覆盖

题目&#xff1a; 给出一张nn(n≤100) 的国际象棋棋盘&#xff0c;其中被删除了一些点&#xff0c;问可以使用多少1*2的多米 诺骨牌进行掩盖。 题解&#xff1a; 先进行黑白染色&#xff0c;相邻的两个黑白就是一个骨牌&#xff0c;又因为一个格子不能放多个骨牌&#xff0c;…

P5494-[模板]线段树分裂

正题 题目链接:https://www.luogu.com.cn/problem/P5494 题目大意 给出一个可重集合要求支持 将集合ppp中在[l,r][l,r][l,r]的数放到一个新的集合中将集合ttt的所有数放入集合ppp中在集合ppp中放入xxx个ppp查询集合ppp中在[l,r][l,r][l,r]区间的数查询集合ppp中第kkk小的数 …

暑期训练待补

2021牛客暑期多校训练营5 C-Cheating and Stealing 繁琐 F-Finding Points 计算几何 I-Interval Queries 回滚莫队链表 2021牛客暑期多校训练营6 D-Gambling Monster FWT G-Hasse Diagram min25筛 2021牛客暑期多校训练营7 A-xay loves connected graphs多项式&#xff1f…