[日常摸鱼]loj6000「网络流 24 题」搭配飞行员

题面

应该是二分图匹配,不过我写的是网络最大流。

dinic求二分图最大匹配:加个源点和汇点,源点连向二分图的一边所有点,二分图的另一边所有点连向汇点,很明显这样得到的最大流就是这个二分图的最大匹配。

#include<cstdio>
#include<algorithm>
#define rep(i,n) for(register int i=1;i<=n;i++)
#define REP(i,a,b) for(register int i=a;i<=b;i++)
using namespace std;
const int N=105;
const int M=10205;
const int INF=(~0u>>1);
struct edge
{
    int to,nxt,w;
    edge(int to=0,int nxt=0,int w=1):to(to),nxt(nxt),w(w){}
}edges[M<<1];
int n,m,cnt,st,ed,s,t,ans;
int head[M<<1],d[N],q[N];
inline void addEdge(int u,int v)
{
    edges[++cnt]=edge(v,head[u]);
    head[u]=cnt;
    edges[++cnt]=edge(u,head[v],0);
    head[v]=cnt;
}
#define cur edges[i].to
inline bool bfs()
{
    rep(i,t)d[i]=0;d[s]=1;
    st=ed=0;q[st++]=s;
    while(ed<st)
    {
        int k=q[ed++];
        for(register int i=head[k];i;i=edges[i].nxt)if(edges[i].w&&!d[cur])
        {
            d[cur]=d[k]+1;q[st++]=cur;
            if(cur==t)return 1;
        }
    }
    return 0;
}
inline int dinic(int x,int f)
{
    if(x==t)return f;
    int res=f;
    for(register int i=head[x];i&&res;i=edges[i].nxt)if(edges[i].w&&d[cur]==d[x]+1)
    {
        int k=dinic(cur,min(res,edges[i].w));
        if(!k)d[cur]=0;
        edges[i].w-=k;edges[i^1].w+=k;res-=k;
    }
    return f-res;
}
int main()
{
    scanf("%d%d",&n,&m);s=n+1;t=n+2;cnt=1;
    int u,v;
    while(scanf("%d%d",&u,&v)==2)addEdge(u,v);
    REP(i,1,m)addEdge(s,i);
    REP(i,m+1,n)addEdge(i,t);
    int flow=0;
    while(bfs())while((flow=dinic(s,INF)))ans+=flow;
    printf("%d",ans);
    return 0;
}

 

posted @ 2018-02-06 13:04  yoshinow2001  阅读(160)  评论(0编辑  收藏  举报