Dinic二分图匹配 || Luogu P3386

题面:【模板】二分图匹配

思路:Dinic实现二分图匹配,要建一个超级源点(S)和超级汇点(T),分别定为N+M+1和N+M+2

然后S去和N中的数建正边和反边,正边权值为1,反边权值为0;M中的数去与T建正边和反边,正边权值为1。

N、M之间的数建图一样。

然后就去跑最大流。

注意:在Dinic函数中每次更新Cur的值时,要把S和T的Cur也更新了。

代码:

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 #define min(a,b) ((a)<(b)?(a):(b))
 5 using namespace std;
 6 const int maxn=1050,maxm=maxn,maxe=maxm*maxn;
 7 int N,M,u,v,E,num_edge=-1,edge_head[maxn+maxm],Q[maxn+maxm],f1,f2,Dep[maxn+maxm];
 8 int S,T,Cur[maxn+maxm];
 9 struct Edge{int to,nx,dis;}edge[maxe];
10 inline void Add_edge(int from,int to,int dis){
11     edge[++num_edge].nx=edge_head[from];
12     edge[num_edge].to=to;
13     edge[num_edge].dis=dis;
14     edge_head[from]=num_edge;
15     return;
16 }
17 inline bool Bfs(){
18     memset(Dep,0,sizeof(Dep));
19     f1=f2=1;
20     Dep[S]=1;
21     Q[f2++]=S;
22     while(f1<f2){
23         int x=Q[f1++];
24         for(int i=edge_head[x];i!=-1;i=edge[i].nx){
25             int y=edge[i].to;
26             if(edge[i].dis&&Dep[y]==0){
27                 Dep[y]=Dep[x]+1;
28                 Q[f2++]=y;
29             }
30         }
31     }
32     if(Dep[T])return 1;
33     return 0;
34 }
35 inline int Dfs(int x,int fw){
36     if(x==T)return fw;
37     for(int &i=Cur[x];i!=-1;i=edge[i].nx){
38         int y=edge[i].to;
39         if(Dep[y]==Dep[x]+1&&edge[i].dis){
40             int p=Dfs(y,min(edge[i].dis,fw));
41             if(p>0){
42                 edge[i].dis-=p;
43                 edge[i^1].dis+=p;
44                 return p;
45             }
46         }
47     }
48     return 0;
49 }
50 inline int Dinic(){
51     int ans=0;
52     while(Bfs()){
53         int toi=N+M+2;
54         for(int i=1;i<=toi;i++)Cur[i]=edge_head[i];
55         while(int k=Dfs(S,1<<30))ans+=k;
56     }
57     return ans;
58 }
59 int main(){
60     memset(edge_head,-1,sizeof(edge_head));
61     scanf("%d%d%d",&N,&M,&E);
62     S=N+M+1;T=N+M+2;
63     for(int i=1;i<=N;i++){
64         Add_edge(S,i,1);
65         Add_edge(i,S,0);
66     }
67     int toi=N+M;
68     for(int i=N+1;i<=toi;i++){
69         Add_edge(i,T,1);
70         Add_edge(T,i,0);
71     }
72     for(int i=1;i<=E;i++){
73         scanf("%d%d",&u,&v);
74         if(v>M||u>N)continue;
75         v+=N;
76         Add_edge(u,v,1);
77         Add_edge(v,u,0);
78     }
79     printf("%d\n",Dinic());
80     return 0;
81 }


By:AlenaNuna

原文地址:https://www.cnblogs.com/AlenaNuna/p/10959317.html

时间: 2024-07-29 01:54:10

Dinic二分图匹配 || Luogu P3386的相关文章

P3386 【模板】二分图匹配

洛谷—— P3386 [模板]二分图匹配 题目背景 二分图 题目描述 给定一个二分图,结点个数分别为n,m,边数为e,求二分图最大匹配数 输入输出格式 输入格式: 第一行,n,m,e 第二至e+1行,每行两个正整数u,v,表示u,v有一条连边 输出格式: 共一行,二分图最大匹配 输入输出样例 输入样例#1: 1 1 1 1 1 输出样例#1: 1 说明 n,m<=1000,1<=u<=n,1<=v<=m 因为数据有坑,可能会遇到v>m的情况.请把v>m的数据自觉过

洛谷—— P3386 【模板】二分图匹配

https://www.luogu.org/problem/show?pid=3386 题目背景 二分图 题目描述 给定一个二分图,结点个数分别为n,m,边数为e,求二分图最大匹配数 输入输出格式 输入格式: 第一行,n,m,e 第二至e+1行,每行两个正整数u,v,表示u,v有一条连边 输出格式: 共一行,二分图最大匹配 输入输出样例 输入样例#1: 1 1 1 1 1 输出样例#1: 1 说明 n,m<=1000,1<=u<=n,1<=v<=m 因为数据有坑,可能会遇到v

AC日记——【模板】二分图匹配 洛谷 P3386

题目背景 二分图 题目描述 给定一个二分图,结点个数分别为n,m,边数为e,求二分图最大匹配数 输入输出格式 输入格式: 第一行,n,m,e 第二至e+1行,每行两个正整数u,v,表示u,v有一条连边 输出格式: 共一行,二分图最大匹配 输入输出样例 输入样例#1: 1 1 1 1 1 输出样例#1: 1 说明 n,m<=1000,1<=u<=n,1<=v<=m 因为数据有坑,可能会遇到v>m的情况.请把v>m的数据自觉过滤掉. 算法:二分图匹配 思路: 二分图模

二分图匹配([洛谷]P3386 模板 二分图匹配)

二分图匹配其实十分简单,原理只有一个,能换则换,腾出这个妹子的位置,不要考虑其他人是不是很不满意从他喜欢中最喜欢的那一个变成了他喜欢中的最不喜欢的那一个,知道了这个原理,n遍DFS就可以过了: #include<stdio.h> #include<string.h> const int Inf=1e9+10,maxn=5010,maxm=5010,maxe=10010; int gi(){ int sum=0,f=1;char ch=getchar(); while(ch>'

二分图匹配(入门篇)

二分图匹配 write by BigYellowDog 1. 什么是二分图? 有一个无向图,如果所有的点可以被所有的边分成两个点集.则说这个图为二分图 下图就是一个标准二分图: 2. 什么是二分图匹配? 现有一个二分图E,还有它的子集M.如果M中任意一条边都没有公共的端点.则M是一个"匹配" 如果一个匹配M'中边数是所有匹配中最多的,则说M'为"最大匹配" 如果匹配M中,所有点都得到了一一匹配,则说M是一个"完全匹配" 如上图(不用管最下面那一行

luoguP3386 【模板】二分图匹配

P3386 [模板]二分图匹配 题目背景 二分图 感谢@一扶苏一 提供的hack数据 题目描述 给定一个二分图,结点个数分别为n,m,边数为e,求二分图最大匹配数 输入输出格式 输入格式: 第一行,n,m,e 第二至e+1行,每行两个正整数u,v,表示u,v有一条连边 输出格式: 共一行,二分图最大匹配 输入输出样例 输入样例#1: 复制 1 1 1 1 1 输出样例#1: 复制 1 说明 因为数据有坑,可能会遇到 v>mv>m 的情况.请把 v>mv>m 的数据自觉过滤掉. 算法

POJ2584 T-Shirt Gumbo 二分图匹配(网络流)

1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 5 const int inf=0x3f3f3f3f; 6 const int sink=30; 7 8 struct Edge 9 { 10 int to; 11 int next; 12 int capacity; 13 14 void assign(int t,int n,int c) 15 { 16 to=t; next=n; ca

cogs_396_魔术球问题_(最小路径覆盖+二分图匹配,网络流24题#4)

描述 http://cojs.tk/cogs/problem/problem.php?pid=396 连续从1开始编号的球,按照顺寻一个个放在n个柱子上,\(i\)放在\(j\)上面的必要条件是\(i+j\)是一个完全平方数.问做多能放到几号球. 分析 cogs是简化版,我在网上找了个完整版的测试数据,要求输出方案... 求最大放几号球不方便,我们考虑枚举最大的球号,计算最少需要多少柱子. 我们对于满足\(j<i\)且\(i+j\)是一个完全平方数的\(i,j\),从\(j\)向\(i\)连一条

HDU 5093 Battle ships(二分图匹配)

该题是一道经典的二分图匹配题目 .  同一列(行)上不能放两个船除非有冰山隔着.对于这种二维平面图,我们很容易想到将行和列分成两个集合,进行二分图匹配,当一个行坐标匹配到一个列坐标时,该格子可以放置船.那么为了使任意两个船都不在同一行或者同一列,除非有冰山,我们可以将每一行中一块连续的只能放置一个船的区域都设成一个编号,同样的按照列也这样处理,这样就相当于将行和列缩点了,接下来用最大流模板套一套就可以了 . 处理二分图还有一种更好的算法,叫匈牙利算法,紫书上没有,先用最大流算法解决吧 . 紫书十