二分图(例题)

news/2024/9/26 2:14:55
    https://www.cnblogs.com/kuangbiaopilihu/p/18184536

$\quad $ 这里不再介绍二分图的基础知识,只是一些例题的解释。

$\quad $ 当然,这道题可以用二分+并查集来解决。但这是二分图专辑,所以介绍一下二分图做法。
$\quad $ 首先如果两个罪犯之间有仇恨,那么当他们不在同一所监狱时不会发生冲突。若要若干个罪犯之间不产生冲突,那么将有仇恨的罪犯连边,则不会发生冲突的罪犯恰好形成一个二分图。
$\quad $ 所以按照有仇恨罪犯之间的怒气值排序,再二分一下答案下标,把边权大于二分答案的边加进去,如果形成了一个二分图,则答案合法。然后便可得出答案。

点击查看代码
  #include<bits/stdc++.h>using namespace std;const int N=1e5+100;vector<int> sl[N];struct stu{int x,y,w;}s[N];int col[N],n,m,ans;bool is_gragh(int cur,int fa,int color){col[cur]=color;for(int i=0;i<sl[cur].size();i++){int y=sl[cur][i];if(col[y]==color)return false;if(col[y]==0&&!is_gragh(y,cur,3-color))return false;}return true;}bool check(int x){for(int i=1;i<=n;i++)sl[i].clear();memset(col,0,sizeof col);for(int i=x+1;i<=m;i++){int x=s[i].x,y=s[i].y;sl[x].push_back(y);sl[y].push_back(x);}for(int i=1;i<=n;i++)if(col[i]==0)if(!is_gragh(i,0,1))return false;return true;}bool cmp(stu a,stu b){return a.w<b.w;}int main(){scanf("%d%d",&n,&m);for(int i=1;i<=m;i++)scanf("%d%d%d",&s[i].x,&s[i].y,&s[i].w);sort(s+1,s+1+m,cmp);int l=0,r=m;while(l<=r){int mid=(l+r)>>1;if(check(mid))r=mid-1,ans=mid;else l=mid+1;}printf("%d",s[ans].w);return 0;}

$\quad $ 可以发现,如果选择了一列,那么处于这一列的点将都被消除,那么就可以将该点与其所在行与所在列相连,以表示其关联。先拿样例举例:

$\quad $ 我们发现,点只存在于行和列之间的边上,那么将点省去,可以得到一个二分图。这样问题就变为了一个二分图的点最大覆盖问题,求最大匹配即可。

点击查看代码
#include<bits/stdc++.h>using namespace std;const int N=1e4+100;bool vis[N];int n,k,match[N];vector<int> s[N<<1];bool dfs(int x){for(int i=0;i<s[x].size();i++){int y=s[x][i];if(!vis[y]){vis[y]=1;if(!match[y]||dfs(match[y])){match[y]=x;return true;}}}return false;}int Hungary(){int ans=0;for(int i=1;i<=n;i++){memset(vis,0,sizeof vis);if(dfs(i))ans++;}return ans;}int main(){scanf("%d%d",&n,&k);n<<=1;for(int i=1;i<=k;i++){int x,y;scanf("%d%d",&x,&y);y+=n;s[x].push_back(y);s[y].push_back(x);}printf("%d",Hungary());return 0;}

$\quad $ 还是先膜样例,这里用汉字表示锦囊,阿拉伯数字表示题目。

$\quad $ 同样可以得到一张二分图,只不过这道题不是要求最大匹配,因为答题出现错误就淘汰了,仔细观察匈牙利算法代码,可以发现他正是从1顺序开始寻找的,所以我们只要在无法匹配时打断循环即可。

点击查看代码
#include<bits/stdc++.h>using namespace std;const int N=1e4+100;bool vis[N];int n,k,match[N];vector<int> s[N<<1];bool dfs(int x){for(int i=0;i<s[x].size();i++){int y=s[x][i];if(!vis[y]){vis[y]=1;if(!match[y]||dfs(match[y])){match[y]=x;return true;}}}return false;}int Hungary(){int ans=0;for(int i=1;i<=n;i++){memset(vis,0,sizeof vis);if(dfs(i))ans++;else break;}return ans;}int main(){scanf("%d%d",&n,&k);for(int i=1;i<=k;i++){int x,y;scanf("%d%d",&x,&y);x++,y++;s[i].push_back(y);s[i].push_back(x);}printf("%d",Hungary());return 0;}

$\quad $ 先求出所有小衫到所有出口所需时间,对时间小于k的情况,就将两者相连,最后还是的到一张二分图,此时只需要求出最大匹配即可。
注意开double!!

点击查看代码
  #include<bits/stdc++.h>using namespace std;const int N=1e4+100;bool vis[N];int n,k,match[N],m;vector<int> s[N<<1];double x[N],y[N];bool dfs(int x){for(int i=0;i<s[x].size();i++){int y=s[x][i];if(!vis[y]){vis[y]=1;if(!match[y]||dfs(match[y])){match[y]=x;return true;}}}return false;}int Hungary(){int ans=0;for(int i=1;i<=m;i++){memset(vis,0,sizeof vis);if(dfs(i))ans++;}return ans;}int main(){scanf("%d%d%d",&m,&n,&k);//m是小衫个数,n是点数,k是边权最大值。for(int i=1;i<=n;i++)scanf("%lf%lf",&x[i],&y[i]);for(int i=1;i<=m;i++){double xl,yl,vl,tl;scanf("%lf%lf%lf",&xl,&yl,&vl);for(int j=1;j<=n;j++){tl=sqrt((x[j]-xl)*(x[j]-xl)+(y[j]-yl)*(y[j]-yl));tl/=vl;// cout<<tl<<endl;if(k>=tl)s[i].push_back(j+m),s[j+m].push_back(i);}}printf("%d",Hungary());return 0;}

$\quad $ 这道题和穿越小行星群很像,但是有石头阻拦,对于有石头阻拦的,我们可以将一行视为两行、一列视为两列,再将合法的位置与其行列连边。这样又得到一张二分图,再求最大匹配即可。

点击查看代码
#inclu  de<bits/stdc++.h>using namespace std;const int N=65;char ch[N*N][N*N];bool vis[N*N];int n,m,match[N*N],row[N*N][N*N],col[N*N][N*N];int ntot,ltot;vector<int>s[N*N];bool dfs(int x){for(int i=0;i<s[x].size();i++){int y=s[x][i];if(!vis[y]){vis[y]=1;if(!match[y]||dfs(match[y])){match[y]=x;return true;}}}return false;}int Hungary(){int ans=0;for(int i=1;i<=ntot;i++){memset(vis,0,sizeof vis);if(dfs(i))ans++;}return ans;}int main(){scanf("%d%d",&m,&n);for(int i=1;i<=m;i++)scanf("%s",ch[i]+1);for(int i=1;i<=m;i++){for(int j=1;j<=n;j++){if(ch[i][j]-'#'){if(j>1&&ch[i][j-1]-'#')row[i][j]=row[i][j-1];else row[i][j]=++ntot;if(i>1&&ch[i-1][j]-'#')col[i][j]=col[i-1][j];else col[i][j]=++ltot;}}}for(int i=1;i<=m;i++){for(int j=1;j<=n;j++){if(ch[i][j]=='o')s[row[i][j]].push_back(col[i][j]+ntot);}}printf("%d",Hungary());}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈,一经查实,立即删除!

相关文章

记一次阿里云服务器被ssh爆破

查看Ubuntu登录日志: cat /var/log/auth.log 发现我的服务器被ssh爆破针对这一现象 我决定构造一个脚本 来防范这种爆破式攻击 具体思路就是通过脚本判定特定IP的登录失败次数 如果多于两次 关闭进程 并且ban IP 首先就是将登录失败的ip单独拎出来 cat /var/log/auth.log.1 | …

海康威视

1 static关键字作用 修饰局部变量 ​ static修饰局部变量时,使得被修饰的变量成为静态变量,存储在静态区。存储在静态区的数据生命周期与程序相同,在main函数之前初始化,在程序退出时销毁。(无论是局部静态还是全局静态) 修饰全局变量 ​ 全局变量本来就存储在静态区,因…

.net core 实现注册同一服务类型的多个服务实例

1. 注册服务。给 IMyDependency 注册两个不同的实现。builder.Services.AddSingleton<IMyDependency, MyDependency>(); builder.Services.AddSingleton<IMyDependency, DifferentDependency>();2. 依赖注入。通过 IEnumerable<IMyDependency> 获取两个不同的…

PWN的一些前置知识

PWN的一些前置知识点 虽然我超想打web方向,但是其实感觉每个方向都一窍不通555,算了先学学pwn和misc再说吧 大致流程 查看文件 使用checksec命令,查看是否开启PIE,ASLR等,查看是否有canary(栈保护的机制) 静态分析 使用IDA pro或者其他静态分析软件,获取软件逆向代码 动…

多版本同时维护的 Bug 修复源代码保存方案

问题描述 在日常维护系统的过程中,我们经常需要修复他人提交的 Bug(因为自己写的都是 feature 嘛)。对于单个线上版本的项目,我们可以轻松地创建一个 bug 修复分支,修复完成后再将其合并到主分支即可。 然而,当系统同时存在多个线上版本时,比如 V1.0.1、V1.0.2、V1.0.3、…

汇编(机器码)

2440常用汇编指令https://blog.csdn.net/weixin_58016534/article/details/131180529

HTTP 连接详解

概述 世界上几乎所有的 HTTP 通信都是由 TCP/IP 承载的,客户端可以打开一条TCP/IP连接,连接到任何地方的服务器。一旦连接建立,客户端和服务器之间交换的报文就永远不会丢失、受损或失序 TCP(Transmission Control Protocol)传输控制协议,是一种面向连接的、可靠的、基于…

redis之主从复制

1.基本环境(1) Lunix centos7(2) redis版本:redis7.0.0(3) gcc已经配置成功,并且默认redis7.0.0环境已经在linux中做好了 2.架构说明(1) 一个master两salve (方便期间配置好一个后,其他两个配置文件修改即可)① Master : 10.0.0.18 6379② Slave1: 10.0.0.19 6380③ Slave…