【网络流24题】搭配飞行员(最大流+二分图匹配)

传送门

    搭配飞行员
    题意:二分图匹配裸题,不多说

I think

    Dinic算法跑最大流解决||匈牙利算法

Code

代码一:Dinic

#include<cstdio>
#include<queue>
#include<cstring>
using namespace std;
const int sm = 105,sn=sm*sm+200;
const int Inf = 0x3f3f3f3f;
int S,T;
int M,N,tot=1,Flow;
int to[sn],nxt[sn],c[sn],hd[sm];
int pre[sm],lev[sm],cur[sm];
void Add(int u,int v) {
    to[++tot]=v,nxt[tot]=hd[u],hd[u]=tot,c[tot]=1;
    to[++tot]=u,nxt[tot]=hd[v],hd[v]=tot,c[tot]=0;
}
int Bk() {
    int t,f=Inf,g;
    for(int i=pre[T];i;i=pre[i])
        if(c[cur[i]]<=f) 
            f=c[cur[i]],g=i;
    for(int i=pre[T];i;i=pre[i]) {
        c[cur[i]]-=f;
        c[cur[i]^1]+=f;
    }
    Flow+=f;
    return g;
}
bool Bfs() {
    int t;
    lev[S]=1;
    queue<int>Que;
    Que.push(S);
    while(!Que.empty()) {
        t=Que.front(),Que.pop();
        for(int i=hd[t];i;i=nxt[i]) 
            if(!lev[to[i]]&&c[i]>0) {
                lev[to[i]]=lev[t]+1;
                if(to[i]==T) return true;
                Que.push(to[i]);
            }
    }
    return false;
}
void Dfs() {
    int t=S; bool fl;
    while(t) {
        fl=0;
        int i=cur[t]?nxt[cur[t]]:hd[t];
        for(;i;i=nxt[i]) 
            if(lev[to[i]]==lev[t]+1&&c[i]>0) {
                cur[t]=i,pre[to[i]]=t;
                fl=true,t=to[i];
                if(to[i]==T) t=Bk();
                break;
            }
        if(!fl) { lev[t]=0; t=pre[t]; }
    }
}
int main() {
    int u,v;
    scanf("%d%d",&N,&M);
    while(scanf("%d%d",&u,&v)!=EOF) Add(u,v);
    S=N+1,T=N+2;
    for(int i=1;i<=N;++i)
        if(i<=M) Add(S,i);
        else Add(i,T);
    while(Bfs()) Dfs();
    printf("%d\n",Flow);
    return 0;
}

代码二:匈牙利算法

#include<cstdio>
using namespace std;

const int sm = 1e2+5;
const int sn = sm*sm;

int N,M,tot,Ans;
int to[sn],hd[sm],nxt[sn];
int p[sm],vis[sm];

void Add(int u,int v) {
    to[++tot]=v,nxt[tot]=hd[u],hd[u]=tot;
}
bool HG(int x) {
    for(int i=hd[x];i;i=nxt[i]) 
        if(!vis[to[i]]) {
            vis[to[i]]=true;
            if(!p[to[i]]||HG(p[to[i]])){
                p[to[i]]=x,p[x]=to[i];
                return true;
            }
        }
    return false;
}
int main() {
    int u,v;
    scanf("%d%d",&M,&N);
    while(scanf("%d%d",&u,&v)!=EOF)
        Add(u,v);
    for(int i=1;i<=M;++i) 
        if(!p[i]) {
            for(int j=M+1;j<=N;++j)
                vis[j]=0;
            if(HG(i)) ++Ans;
            else p[i]=0;
        }
    printf("%d\n",Ans);
    return 0;
}           
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值