1. 程式人生 > 實用技巧 >洛谷 p2756 飛行員配對方案問題(最大流,二分圖匹配)

洛谷 p2756 飛行員配對方案問題(最大流,二分圖匹配)

題目

題目背景
第二次世界大戰期間,英國皇家空軍從淪陷國徵募了大量外籍飛行員。由皇家空軍派出的每一架飛機都需要配備在航行技能和語言上能互相配合的兩名飛行員,其中一名是英國飛行員,另一名是外籍飛行員。在眾多的飛行員中,每一名外籍飛行員都可以與其他若干名英國飛行員很好地配合。

題目描述
一共有 nn 個飛行員,其中有 mm 個外籍飛行員和 (n - m)(n−m) 個英國飛行員,外籍飛行員從 11 到 mm 編號,英國飛行員從 m + 1m+1 到 nn 編號。 對於給定的外籍飛行員與英國飛行員的配合情況,試設計一個演算法找出最佳飛行員配對方案,使皇家空軍一次能派出最多的飛機。

輸入格式
輸入的第一行是用空格隔開的兩個正整數,分別代表外籍飛行員的個數 mm 和飛行員總數 nn。
從第二行起到倒數第二行,每行有兩個整數 u, vu,v,代表外籍飛行員 uu 可以和英國飛行員 vv 配合。
輸入的最後一行保證為 -1 -1,代表輸入結束。

輸出格式
本題存在 Special Judge。
請輸出能派出最多的飛機數量,並給出一種可行的方案。
輸出的第一行是一個整數,代表一次能派出的最多飛機數量,設這個整數是 kk。
第 22 行到第 k + 1k+1 行,每行輸出兩個整數 u, vu,v,代表在你給出的方案中,外籍飛行員 uu 和英國飛行員 vv 配合。這 kk 行的 uu 與 vv 應該互不相同。

思路

二分圖最大匹配,我們用dinic跑一邊就好了。

程式碼實現

#include<cstdio>
#include<algorithm>
#include<vector>
#include<queue>
#include<map>
#include<iostream>
#include<cstring>
#include<cmath>
using namespace std;
#define rep(i,f_start,f_end) for (int i=f_start;i<=f_end;++i)
#define per(i,n,a) for (int i=n;i>=a;i--)
#define MT(x,i) memset(x,i,sizeof(x) )
#define rev(i,start,end) for (int i=start;i<end;i++)
#define inf 0x3f3f3f3f
#define mp(x,y) make_pair(x,y)
#define lowbit(x) (x&-x)
#define MOD 1000000007
#define exp 1e-8
#define N 1000005 
#define fi first 
#define se second
#define pb push_back
typedef long long ll;
typedef vector <int> VI;
typedef pair<int ,int> PII;
typedef pair<int ,PII> PIII;
ll gcd (ll a,ll b) {return b?gcd (b,a%b):a; }
inline int read() {
    char ch=getchar(); int x=0, f=1;
    while(ch<'0'||ch>'9') {
        if(ch=='-') f = -1;
        ch=getchar();
    } 
    while('0'<=ch&&ch<='9') {
        x=x*10+ch-'0';
        ch=getchar();
    }   return x*f;
}

const int maxn=1e5+10;
struct edge {
    int v,flow,next;
}e[maxn];
int head[maxn],cnt=-1;

inline void add (int u,int v,int flow) {
    e[++cnt]=(edge) {v,flow,head[u]};
    head[u]=cnt;
}
inline void add_edge (int u,int v,int flow) {
    add (u,v,flow);
    add (v,u,0);
}

int dis[maxn],cur[maxn];
int s,t,n,m,ans,x,y;
int bfs () {
    MT (dis,0);
    queue<int > q;
    q.push (s);
    dis[s]=1;
    while (q.size ()) {
        int x=q.front (); q.pop ();
        for (int i=head[x];i!=-1;i=e[i].next) {
            if (dis[e[i].v]==0&&e[i].flow) {
                dis[e[i].v]=dis[x]+1;
                q.push (e[i].v);
            }
        }
    }
    return dis[t];
}

int dfs (int now,int nowflow) {
    if (now==t) return nowflow;
    for (int &i=cur[now];~i;i=e[i].next) {
        if (dis[e[i].v]==dis[now]+1&&e[i].flow) {
            int canflow=dfs (e[i].v,min (nowflow,e[i].flow));
            if (canflow>0) {
                e[i].flow-=canflow;
                e[i^1].flow+=canflow;
                return canflow;
            }
        }
    }
    return 0;
}

void Dinic () {
    while (bfs ()) {
       for (int i=s;i<=t;i++) cur[i]=head[i];
       while (int val=dfs(s,inf)) ans+=val;
    }
}
int main () {
    cin>>m>>n;
    MT (head,-1);
    s=0,t=n+1;
    rep (i,1,m) add_edge (s,i,1);
    rep (i,m+1,n) add_edge (i,t,1);

    while (scanf ("%d%d",&x,&y)&&x!=-1&&y!=-1) add_edge (x,y,1);
    Dinic ();
    if (!ans) {
        cout<<"no answer"<<endl;
    }
    else {
        cout<<ans<<endl;
        rep (i,1,m) 
            for (int j=head[i];~j;j=e[j].next) 
                if (e[j].flow==0&&e[j^1].flow==1&&i!=s&&i!=t&&e[j].v!=s&&e[j].v!=t) 
                   printf ("%d %d\n",i,e[j].v); 
    }
    return 0;
}