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的数据自觉过滤掉。

算法:二分图匹配

思路:

  二分图模板;

来,上代码:

#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

#define maxn 1005
#define INF 0x7fffffff

using namespace std;

struct EdgeType {
    int v,f,e;
};
struct EdgeType edge[maxn*maxn*2];

int cnt,deep[maxn<<1],ans,e;
int n,m,head[maxn<<1],s=0,t=(maxn<<1)-1;

char Cget;

inline void in(int &now)
{
    now=0,Cget=getchar();
    while(Cget>‘9‘||Cget<‘0‘) Cget=getchar();
    while(Cget>=‘0‘&&Cget<=‘9‘)
    {
        now=now*10+Cget-‘0‘;
        Cget=getchar();
    }
}

bool bfs()
{
    for(int i=s;i<=t;i++) deep[i]=-1;
    queue<int>que;deep[s]=0,que.push(s);
    while(!que.empty())
    {
        int now=que.front();que.pop();
        for(int i=head[now];i;i=edge[i].e)
        {
            if(edge[i].f>0&&deep[edge[i].v]<0)
            {
                deep[edge[i].v]=deep[now]+1;
                if(edge[i].v==t) return true;
                que.push(edge[i].v);
            }
        }
    }
    return false;
}

int flowing(int now,int flow)
{
    if(now==t||flow<=0) return flow;
    int oldflow=0;
    for(int i=head[now];i;i=edge[i].e)
    {
        if(edge[i].f<=0||deep[edge[i].v]!=deep[now]+1) continue;
        int pos=flowing(edge[i].v,min(edge[i].f,flow));
        if(pos>0)
        {
            flow-=pos;
            oldflow+=pos;
            edge[i].f-=pos;
            edge[i^1].f+=pos;
            if(flow==0) return oldflow;
        }
    }
    if(oldflow==0) deep[now]=-1;
    return oldflow;
}

int main()
{
    in(n),in(m),in(e);
    for(int i=1;i<=n;i++)
    {
        edge[++cnt].v=i,edge[cnt].f=1,edge[cnt].e=head[s],head[s]=cnt;
        edge[++cnt].v=s,edge[cnt].f=0,edge[cnt].e=head[i],head[i]=cnt;
    }
    for(int i=1+n;i<=m+n;i++)
    {
        edge[++cnt].v=t,edge[cnt].f=1,edge[cnt].e=head[i],head[i]=cnt;
        edge[++cnt].v=i,edge[cnt].f=0,edge[cnt].e=head[t],head[t]=cnt;
    }
    int u,v;
    while(e--)
    {
        in(u),in(v);v+=n;
        edge[++cnt].v=v,edge[cnt].f=1,edge[cnt].e=head[u],head[u]=cnt;
        edge[++cnt].v=u,edge[cnt].f=0,edge[cnt].e=head[v],head[v]=cnt;
    }
    while(bfs()) ans+=flowing(s,INF);
    cout<<ans;
    return 0;
}
时间: 2024-10-12 23:55:01

AC日记——【模板】二分图匹配 洛谷 P3386的相关文章

二分图匹配([洛谷]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>'

AC日记——双栈排序 洛谷 P1155

双栈排序 思路: 二分图染+模拟: 代码: #include <bits/stdc++.h> using namespace std; #define maxn 1005 #define maxm 2000005 int n,head[maxn],E[maxm],V[maxm],cnt,col[maxn]; int minn[maxn],ai[maxn],sta1[maxn],sta2[maxn],top1,top2; bool if_[maxn][maxn]; inline void in(

AC日记——[SDOI2010]大陆争霸 洛谷 P3690

[SDOI2010]大陆争霸 思路: dijkstra模板: 代码: #include <bits/stdc++.h> using namespace std; #define maxn 3005 #define ll long long #define maxm 70002<<2 #define INF 1e13 struct NodeType { ll id,dis; bool operator<(const NodeType pos)const { return dis

AC日记——联合权值 洛谷 P1351

题目描述 无向连通图G 有n 个点,n - 1 条边.点从1 到n 依次编号,编号为 i 的点的权值为W i ,每条边的长度均为1 .图上两点( u , v ) 的距离定义为u 点到v 点的最短距离.对于图G 上的点对( u, v) ,若它们的距离为2 ,则它们之间会产生Wu ×Wv 的联合权值. 请问图G 上所有可产生联合权值的有序点对中,联合权值最大的是多少?所有联合权值之和是多少? 输入输出格式 输入格式: 输入文件名为link .in. 第一行包含1 个整数n . 接下来n - 1 行,

AC日记——松江1843路 洛谷七月月赛

松江1843路 思路: 三分: 代码: #include <bits/stdc++.h> using namespace std; #define maxn 100005 #define ll long long struct DataType { ll pi,val,sumval,sumpi; bool operator<(const DataType pos)const { return pi<pos.pi; } }; struct DataType ai[maxn]; ll

AC日记——[HAOI2015]树上操作 洛谷 P3178

题目描述 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个操作,分为三种:操作 1 :把某个节点 x 的点权增加 a .操作 2 :把某个节点 x 为根的子树中所有点的点权都增加 a .操作 3 :询问某个节点 x 到根的路径中所有点的点权和. 输入输出格式 输入格式: 第一行包含两个整数 N, M .表示点数和操作数.接下来一行 N 个整数,表示树中节点的初始权值.接下来 N-1 行每行三个正整数 fr, to , 表示该树中存在一条边 (fr, to) .再接下来 M 行

AC日记——神奇的幻方 洛谷 P2615(大模拟)

题目描述 幻方是一种很神奇的N*N矩阵:它由数字1,2,3,……,N*N构成,且每行.每列及两条对角线上的数字之和都相同. 当N为奇数时,我们可以通过以下方法构建一个幻方: 首先将1写在第一行的中间. 之后,按如下方式从小到大依次填写每个数K(K=2,3,…,N*N): 1.若(K−1)在第一行但不在最后一列,则将K填在最后一行,(K−1)所在列的右一列: 2.若(K−1)在最后一列但不在第一行,则将K填在第一列,(K−1)所在行的上一行: 3.若(K−1)在第一行最后一列,则将K填在(K−1)

AC日记——逃离僵尸岛 洛谷 P3393

逃离僵尸岛 思路: spfa: 代码: #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; #define maxn 200005 #define maxque 1800056 #define INF 1e12 #define ll long long ll n,m,E[maxque],V[maxque],cnt,

AC日记——封锁阳光大学 洛谷 P1330

封锁阳光大学 思路: bfs染色: 如果当前点能通往已染色的点则不能完成: 图不一定联通: 来,上代码: #include <queue> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; #define maxn 10005 #define maxm 200005 struct EdgeType {