二分图匹配、最大权匹配

匈牙利算法

练习题

过山车 HDU - 2063(二分图匹配)

链接:http://acm.hdu.edu.cn/showproblem.php?pid=2063

题意:每个女生有自己喜欢的男生的列表,问最多能够组成几对?

匈牙利算法

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=500+10;

int k,m,n;
int match[maxn],visit[maxn];
vector<int> G[maxn];

bool dfs(int u)
{
    for(auto v : G[u])
    {
        if(visit[v]) continue;
        visit[v]=true;
        if(!match[v]||dfs(match[v]))
        {
            match[v]=u;
            return true;
        }
    }
    return false;
}

int main()
{
    while(scanf("%d",&k)&&k)
    {
        scanf("%d%d",&m,&n);
        for(int i=1;i<=m;++i) G[i].clear();
        memset(match,0,sizeof(match));

        for(int i=1;i<=k;++i)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            G[u].push_back(v);
        }
        int ans=0;
        for(int i=1;i<=m;++i)
        {
            memset(visit,0,sizeof(visit));
            if(dfs(i)) ans++;
        }
        printf("%d\n",ans);
    }
    return 0;
}

最大流二分图匹配

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=1e6+5,maxm=1e6+5;
const int mod=1e9+7,inf=0x7f7f7f7f;

namespace Dinic
{
    const int MAXN=1e6+10,MAXM=1e6+10;
    int head[MAXN],cur[MAXN],cnt;
    int depth[MAXN];
    int maxvex;//点的数量

    struct Edge
    {
        int nxt,to,flow;
    }edges[MAXM<<1];

    void init(int n)
    {
        maxvex=n;
        cnt=-1;
        memset(head,-1,sizeof(head));
    }

    void add(int u,int v,int flow)
    {
        edges[++cnt]={head[u],v,flow};
        head[u]=cnt;
        edges[++cnt]={head[v],u,0};
        head[v]=cnt;
    }

    bool bfs(int s,int t)
    {
        for(int i=0;i<=maxvex;++i)
            cur[i]=head[i],depth[i]=inf;
        queue<int> q;
        q.push(s);
        depth[s]=0;
        while(!q.empty())
        {
            int u=q.front();
            q.pop();
            for(int i=head[u];i!=-1;i=edges[i].nxt)
            {
                int v=edges[i].to,flow=edges[i].flow;
                if(depth[v]==inf&&flow)
                {
                    depth[v]=depth[u]+1;
                    q.push(v);
                }
            }
        }
        return depth[t]<inf;
    }

    int dfs(int u,int t,int curflow)//当前边的流
    {
        if(curflow==0||u==t)
            return curflow;
        int flow=0,f;
        for(int i=cur[u];i!=-1;i=edges[i].nxt)
        {
            cur[u]=i;//当前弧优化
            int v=edges[i].to,eflow=edges[i].flow;
            if(depth[v]==depth[u]+1&&(f=dfs(v,t,min(curflow,eflow))))
            {
                flow+=f;
                curflow-=f;
                edges[i].flow-=f;
                edges[i^1].flow+=f;
                if(curflow==0)
                    break;
            }
        }
        return flow;
    }

    int Maxflow(int s,int t)
    {
        int cnt=0;
        int flow=0,f;
        while(bfs(s,t))
            while((f=dfs(s,t,inf))>0)
                flow+=f;
        return flow;
    }
};
using namespace Dinic;
int k,m,n;

int main()
{
    while(scanf("%d",&k)&&k)
    {
        scanf("%d%d",&m,&n);
        Dinic::init(m+n+1);
        for(int i=1;i<=m;++i)
            Dinic::add(0,i,1);
        for(int i=1;i<=n;++i)
            Dinic::add(m+i,m+n+1,1);

        for(int i=1;i<=k;++i)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            add(u,v+m,1);
        }
        int ans=Dinic::Maxflow(0,m+n+1);
        printf("%d\n",ans);
    }
    return 0;
}

P3386 【模板】二分图最大匹配

匈牙利算法模板

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=500+10;

int k,m,n,e;
int match[maxn],visit[maxn];
vector<int> G[maxn];

bool dfs(int u)
{
    for(auto v : G[u])
    {
        if(visit[v]) continue;
        visit[v]=true;
        if(!match[v]||dfs(match[v]))
        {
            match[v]=u;
            return true;
        }
    }
    return false;
}

int main()
{
    scanf("%d%d%d",&n,&m,&e);
    memset(match,0,sizeof(match));

    for(int i=1;i<=e;++i)
    {
        int u,v;
        scanf("%d%d",&u,&v);
        G[u].push_back(v);
    }
    int ans=0;
    for(int i=1;i<=n;++i)
    {
        memset(visit,0,sizeof(visit));
        if(dfs(i)) ans++;
    }
    printf("%d\n",ans);
    return 0;
}

KM算法

最大权匹配
参考链接:https://www.cnblogs.com/logosG/p/logos.html
参考链接:https://www.cnblogs.com/jackge/archive/2013/05/03/3057028.html
参考链接:https://www.cnblogs.com/wenruo/p/5264235.html

练习题

奔小康赚大钱 HDU - 2255 (KM算法)

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=300+10;
const int inf=0x3f3f3f3f;

int n;
int match[maxn],visit[maxn];
int pre[maxn],slack[maxn],lx[maxn],ly[maxn],w[maxn][maxn];

void bfs(int u)
{
    ll x,y=0,yy=0,d;
    memset(visit,0,sizeof(visit));
    memset(pre,0,sizeof(pre));
    for(int i=1;i<=n;++i) slack[i]=inf;
    match[y]=u;
    while(1)
    {
        x=match[y],d=inf,visit[y]=1;
        for(int i=1;i<=n;++i)
        {
            if(!visit[i])
            {
                if(slack[i]>lx[x]+ly[i]-w[x][i])
                {
                    slack[i]=lx[x]+ly[i]-w[x][i];
                    pre[i]=y;
                }
                if(slack[i]<d)
                    d=slack[i],yy=i;
            }
        }
        for(int i=0;i<=n;++i)
            if(visit[i])
                lx[match[i]]-=d,ly[i]+=d;
            else
                slack[i]-=d;
        y=yy;
        if(match[y]==-1)
            break;
    }
    while(y)
        match[y]=match[pre[y]],y=pre[y];
}

int km()
{
    memset(match,-1,sizeof(match));
    memset(lx,0,sizeof(lx));
    memset(ly,0,sizeof(ly));
    for(int i=1;i<=n;++i) bfs(i);
    int ans=0;
    for(int i=1;i<=n;++i)
        if(match[i]!=-1)
            ans+=w[match[i]][i];
    return ans;
}

int main()
{
    while(~scanf("%d",&n))
    {
        for(int i=1;i<=n;++i)
            for(int j=1;j<=n;++j)
                scanf("%d",&w[i][j]);
        int ans=km();
        printf("%d\n",ans);
    }
    return 0;
}

J. Spy (KM模板)2019 ICPC Asia Nanjing Regional

在这里插入图片描述

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=400+10;
const int inf=9e18;

int n;
ll a[maxn],p[maxn],b[maxn],c[maxn];
int match[maxn],visit[maxn];
ll pre[maxn],slack[maxn],lx[maxn],ly[maxn],w[maxn][maxn];

void bfs(int u)
{
    ll x,y=0,yy=0,d;
    memset(visit,0,sizeof(visit));
    memset(pre,0,sizeof(pre));
    for(int i=1;i<=n;++i) slack[i]=inf;
    match[y]=u;
    while(1)
    {
        x=match[y],d=inf,visit[y]=1;
        for(int i=1;i<=n;++i)
        {
            if(!visit[i])
            {
                if(slack[i]>lx[x]+ly[i]-w[x][i])
                {
                    slack[i]=lx[x]+ly[i]-w[x][i];
                    pre[i]=y;
                }
                if(slack[i]<d)
                    d=slack[i],yy=i;
            }
        }
        for(int i=0;i<=n;++i)
            if(visit[i])
                lx[match[i]]-=d,ly[i]+=d;
            else
                slack[i]-=d;
        y=yy;
        if(match[y]==-1)
            break;
    }
    while(y)
        match[y]=match[pre[y]],y=pre[y];
}

ll km()
{
    memset(match,-1,sizeof(match));
    for(int i=1;i<=n;++i) bfs(i);
    ll ans=0;
    for(int i=1;i<=n;++i)
        if(match[i])
            ans+=w[match[i]][i];
    return ans;
}

int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;++i) scanf("%lld",&a[i]);
    for(int i=1;i<=n;++i) scanf("%lld",&p[i]);
    for(int i=1;i<=n;++i) scanf("%lld",&b[i]);
    for(int i=1;i<=n;++i) scanf("%lld",&c[i]);
    for(int i=1;i<=n;++i)
        for(int j=1;j<=n;++j)
            for(int k=1;k<=n;++k)
                if(b[i]+c[j]>a[k])
                    w[i][j]+=p[k];
    ll ans=km();
    printf("%lld\n",ans);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值