高一下三调模拟赛5.13(附关于二分图匈牙利建边的详细思考)

· 浏览次数 : 2

小编点评

```c++ #include<bits/stdc++.h>using namespace std;const int N = 4e4 + 10;const int M = 1e7 + 10;int n, a[210][210], tot;bool flag[N];int match[N]; bool vis[N];int head[M], to[M], nxt[M], cnt;void addedge(int x, int y){\tflag[x] = flag[y] = true;\tto[++cnt] = y;\tnxt[cnt] = head[x];\thead[x] = cnt;}bool find(int x){\tfor(int i=head[x]; i; i=nxt[i]){\t\tint y = to[i];\t\tif(!vis[y]){\t\t\tvis[y] = true;\t\t\t\t\t\tif(!match[y] or find(match[y])){\t\t\t\tmatch[y] = x;\t\t\t\treturn true;\t\t\t\t}\t\t}\treturn false;}int Hun(){\tint ans = 0;\tfor(int i=1; i<=tot; i++){\t\tmemset(vis, 0, sizeof(vis));\t\tif(find(i)) ans++;\t}\treturn ans;}void con(int i, int j){\tint now = a[i][j];\tif(a[i-1][j-2]) addedge(now, a[i-1][j-2]);\tif(a[i-2][j-1]) addedge(now, a[i-2][j-1]);\tif(a[i+1][j-2]) addedge(now, a[i+1][j-2]);\tif(a[i+2][j-1]) addedge(now, a[i+2][j-1];\tif(a[i-1][j+2]) addedge(now, a[i-1][j+2]);\tif(a[i-2][j+1]) addedge(now, a[i-2][j+1]);\tif(a[i+1][j+2]) addedge(now, a[i+1][j+2]);\tif(a[i+2][j+1]) addedge(now, a[i+2][j+1]);}int main(){\tfreopen("attack.in", "r", stdin);\tfreopen("attack.out", "w", stdout);\t\tscanf(\"%d\", &n);\tfor(int i=1; i<=n; i++){\t\tfor(int j=1; j<=n; j++){\t\t\tchar in; cin>>in;\t\t\tif(in == '0') a[i][j] = ++tot;\t\t}\t}\tfor(int i=1; i<=n; i++){\t\tfor(int j=1; j<=n; j++){\t\t\if(a[i][j])\tcon(i, j);\t\t}\t}\t\tprintf(\"%d\", tot - Hun() / 2);\t\treturn 0;}B. 循环C. 漫步D. 穿越E. 结队。归纳总结以上内容,生成内容时需要带简单的排版 ```

正文

前言注:本篇为知识性内容,A题附详解关于匈牙利算法求最大独立子集难以理解的建边问题的思考,若有不当之处感谢指出。暂时只写了A篇题解,以供帮助大家理解相关问题,剩余题解会进行补充。

又是小集训的一周,总要伴随着模拟赛...

还是五道题目:

A. 攻击装置
B. 循环
C. 漫步
D. 穿越
E. 结队

赛时拿了230...太菜了,本来预料中ABC全 $ AC $ 的,结果出乎意料地windows + dev给了我当头一棒,我不管,就是他俩的锅, 谁让dev开了O2也不给我报错, 导致我C题

$ Compile  Error$
(重载运算符operator 前没加bool类型)

  

  • A. 攻击装置

题目

赛前huge就已经告诉过我们考题有二分图,再看到这个题“装置互不攻击”,明显了,直接开打,但因为建边问题调了一个小时才搓出来,有点慢了。可能昨天做的二分图专题对于这种求最大独立子集为什么建双边不是很明白,这个题虽说用时长了点,但却让我明白了建双边的意义。就这个题叙述一下。

建边操作如下:

void con(int i, int j){
	int now = a[i][j];
	if(a[i-1][j-2]) addedge(now, a[i-1][j-2]);
	if(a[i-2][j-1]) addedge(now, a[i-2][j-1]);
	if(a[i+1][j-2]) addedge(now, a[i+1][j-2]);
	if(a[i+2][j-1]) addedge(now, a[i+2][j-1]);
	if(a[i-1][j+2]) addedge(now, a[i-1][j+2]);
	if(a[i-2][j+1]) addedge(now, a[i-2][j+1]);
	if(a[i+1][j+2]) addedge(now, a[i+1][j+2]);
	if(a[i+2][j+1]) addedge(now, a[i+2][j+1]);
}

即对于每一个点,将其所可以攻击到的点建上单向边,不过当然,now点遍历到现在连向的点后,还会再连回来一条边。
赛时就一直在想能不能只建单向边,

像这样:
void con(int i, int j){
	int now = a[i][j];
	if(a[i-1][j-2]) addedge(now, a[i-1][j-2]);
	if(a[i-2][j-1]) addedge(now, a[i-2][j-1]);
	if(a[i+1][j-2]) addedge(now, a[i+1][j-2]);
	if(a[i+2][j-1]) addedge(now, a[i+2][j-1]);
	// if(a[i-1][j+2]) addedge(now, a[i-1][j+2]);
	// if(a[i-2][j+1]) addedge(now, a[i-2][j+1]);
	// if(a[i+1][j+2]) addedge(now, a[i+1][j+2]);
	// if(a[i+2][j+1]) addedge(now, a[i+2][j+1]);
}
即对于每一个点,我们只连它到下方可攻击到的点:


如图红色为now点可攻击点,但我只连它下方的。
赛时就这么想,可是调半天怎么样也不对,然后思考...突然想明白,
因为这是二分图,我们知道,二分图中点分为两部分,匈牙利算法是把第一部分点连向第二部分,假设我now点为二分图中的第一部分,那么它所攻击的8个点都是第二部分,那么同时这8个点所分别能攻击的64个点也应该是第一部分点。这样的话,按照二分图匈牙利算法建单向边的思路,我需要把这64个点连向上述的那8个点,那么想要这样做的话,把图中的点分为两部分,保证我所有的边都是有第一部分点连向第二部分,这样一来就会很麻烦。
所以呢,我们就有了建双向边的操作。让第一部分点连向第二部分,同时也让第二部分点反向连回第一部分。那么这样我们可以理解为把所有点分为A, B $ 两个部分 $,并建了两个二分图,一个是A作第一部分,其中的点连向B部分中的点,另一个则相反,是B中的点连向A中的点。举个例子:

假定 A 部分有编号为$ 1,3,4 $的三个点, B 部分有$ 2,5,6,7 $四个点,两部分相对应的点建双向边,如图:


我们理解为形成了这样两个二分图,那么跑匈牙利算法的时候等同于又把这两个二分图合二为一,得到了总二分图的最小点覆盖数,且显然两个二分图的最小点覆盖值是相等的,所以我们想要的符合题目的最小点覆盖数即为匈牙利所求的一半,所以最后输出的时候要$ tot-Hun()/2 $

代码如下:

#include<bits/stdc++.h>
using namespace std;

const int N = 4e4 + 10;
const int M = 1e7 + 10;

int n, a[210][210], tot;
bool flag[N];
int match[N]; bool vis[N];

int head[M], to[M], nxt[M], cnt;
void addedge(int x, int y){
	flag[x] = flag[y] = true;
	to[++cnt] = y;
	nxt[cnt] = head[x];
	head[x] = cnt;
}

bool find(int x){
	for(int i=head[x]; i; i=nxt[i]){
		int y = to[i];
		if(!vis[y]){
			vis[y] = true;
			
			if(!match[y] or find(match[y])){
				match[y] = x;
				return true;	
			}
		}
	}
	return false;
}

int Hun(){
	int ans = 0;
	for(int i=1; i<=tot; i++){
		memset(vis, 0, sizeof(vis));
		if(find(i)) ans++;
	}
	return ans;
}

void con(int i, int j){
	int now = a[i][j];
	if(a[i-1][j-2]) addedge(now, a[i-1][j-2]);
	if(a[i-2][j-1]) addedge(now, a[i-2][j-1]);
	if(a[i+1][j-2]) addedge(now, a[i+1][j-2]);
	if(a[i+2][j-1]) addedge(now, a[i+2][j-1]);
	if(a[i-1][j+2]) addedge(now, a[i-1][j+2]);
	if(a[i-2][j+1]) addedge(now, a[i-2][j+1]);
	if(a[i+1][j+2]) addedge(now, a[i+1][j+2]);
	if(a[i+2][j+1]) addedge(now, a[i+2][j+1]);
}

int main(){
	freopen("attack.in", "r", stdin);
	freopen("attack.out", "w", stdout);
	
	scanf("%d", &n);
	for(int i=1; i<=n; i++){
		for(int j=1; j<=n; j++){
			char in; cin>>in;
			if(in == '0') a[i][j] = ++tot;
		}
	}
	for(int i=1; i<=n; i++){
		for(int j=1; j<=n; j++){
			if(a[i][j])	con(i, j);
		}
	}
	
	printf("%d", tot - Hun() / 2);
	
	return 0;
}
  • B. 循环
  • C. 漫步
  • D. 穿越
  • E. 结队

与高一下三调模拟赛5.13(附关于二分图匈牙利建边的详细思考)相似的内容:

高一下三调模拟赛5.13(附关于二分图匈牙利建边的详细思考)

前言注:本篇为知识性内容,A题附详解关于匈牙利算法求最大独立子集难以理解的建边问题的思考,若有不当之处感谢指出。暂时只写了A篇题解,以供帮助大家理解相关问题,剩余题解会进行补充。 又是小集训的一周,总要伴随着模拟赛... 还是五道题目: A. 攻击装置 B. 循环 C. 漫步 D. 穿越 E. 结队

[转帖]x86服务器中网络性能分析与调优(高并发、大流量网卡调优)

最近在百度云做一些RTC大客户的项目,晚上边缘计算的一台宿主机由于CPU单核耗被打满,最后查到原因是网卡调优没有生效,今天查了一下网卡调优的资料,欢迎大家共同探讨。 一.网卡调优方法 1、Broadcom的网卡建议关闭GRO功能 ethtool -K eth0 gro off ethtool -K

【转帖】x86服务器中网络性能分析与调优(高并发、大流量网卡调优)

最近在百度云做一些RTC大客户的项目,晚上边缘计算的一台宿主机由于CPU单核耗被打满,最后查到原因是网卡调优没有生效,今天查了一下网卡调优的资料,欢迎大家共同探讨。 一.网卡调优方法 1、Broadcom的网卡建议关闭GRO功能 ethtool -K eth0 gro off ethtool -K

【转帖】x86服务器中网络性能分析与调优(高并发、大流量网卡调优)

最近在百度云做一些RTC大客户的项目,晚上边缘计算的一台宿主机由于CPU单核耗被打满,最后查到原因是网卡调优没有生效,今天查了一下网卡调优的资料,欢迎大家共同探讨。 一.网卡调优方法 1、Broadcom的网卡建议关闭GRO功能 ethtool -K eth0 gro off ethtool -K

【转帖】x86服务器中网络性能分析与调优(高并发、大流量网卡调优)

最近在百度云做一些RTC大客户的项目,晚上边缘计算的一台宿主机由于CPU单核耗被打满,最后查到原因是网卡调优没有生效,今天查了一下网卡调优的资料,欢迎大家共同探讨。 一.网卡调优方法 1、Broadcom的网卡建议关闭GRO功能 ethtool -K eth0 gro off ethtool -K

Redis 菜鸟进阶

Redis 菜鸟进阶 背景 最近产品一直要优化性能,加强高可用. 有一个课题是Redis高可用与性能调优. 我这边其实获取到的内容很有限. 最近济南疫情严重,自己锁骨骨折. 然后通勤时间基本上都用来查资料了. 但是毕竟水平有限..简单整理总结一下. 估计纰漏很多..需要进一步学习. 单点 观点: R

【618备战巡礼】“三高”之第一高--如何打造高可用系统

我们经常会说互联网“三高”,那什么是三高呢?我们常说的三高,高并发、高可用、高性能,这些技术是构建现代互联网应用程序所必需的。对于京东618备战来说,所有的中台系统服务,无疑都是围绕着三高来展开的。对于一个程序员,或多或少都能说出一些跟三高系统有关的技术点,而我本篇文章的目的,就是帮大家系统的梳理一下三高系统中的第一高:高可用性

[转帖]浅谈系统稳定性与高可用保障的几种思路

https://segmentfault.com/u/dewujishu 一、前言 高并发、高可用、高性能被称为互联网三高架构,这三者都是工程师和架构师在系统架构设计中必须考虑的因素之一。今天我们就来聊一聊三H中的高可用,也是我们常说的系统稳定性。 本篇文章只聊思路,没有太多的深入细节。阅读全文大概

企业生产环境中的麒麟V10(ARM架构)操作系统部署jdk和redis三主三从交叉版集群

前言:麒麟ARM操作系统是国企和政务机关推行信创化选择率比较高的一款操作系统,然而ARM操作系统非主流的X86系统,除了命令一样,在架构方面差别极大,初次接触多多少少会踩坑,下面我将在公司中部署的实例列举出来,供大家参考,ip和设计机密信息不方便展示,统用虚拟信息代替。 经过多次验证,用了多种通用版

[转帖]Kafka高可用 — KRaft集群搭建

Apache Kafka Raft 是一种共识协议,它的引入是为了消除 Kafka 对 ZooKeeper 的元数据管理的依赖,被社区称之为 Kafka Raft metadata mode,简称 KRaft 模式。本文介绍了KRaft模式及三节点的 KRaft 集群搭建。 1 KRaft介绍 KR