Luo Valley P2756 pilot pairing scheme problem (bipartite graph / network flow, the best matching scheme)

P2756 pilot program pairing problems

Topic background

World War II ..

Title Description

RAF pilots recruited from the fall of a large number of foreign countries. Sent by the Royal Air Force, each aircraft will be equipped with two pilots on the sailing skills and language can cooperate with each other, which is a British pilot, and the other one is a foreign pilots. Among the pilots, every foreign pilots can work well with a number of other British pilot. How to choose the pair to make a flight pilots sent up to the aircraft. For a given situation with foreign pilots and British pilots, test pilots to design an algorithm to find the best pairing scheme, the Royal Air Force, one can send up planes.

For a given situation with foreign pilots and British pilots, pilot program to find the best pairing scheme, the Royal Air Force, one can send up planes.

Input Format

Line 1 has two positive integers m and n. n is the total number of pilot RAF (n <100); m is the number of foreign pilots (m <= n). Foreign pilots numbered 1 ~ m; British pilot number m + 1 ~ n.

Next, each line has two positive integers i and j, i can represent foreign pilots and British pilots with j. Finally, at the end of 2 -1.

Output Format

Line 1 is the maximum number of aircraft pilots the best pairing scheme can once sent M. The next M lines are best paired pilot program. Each row has two positive integers i and j, represent the best pilots in the pairing scheme, the pilot pilots i and j pair. If you ask the best pilots pairing scheme does not exist, then the output 'No Solution!'.

Sample input and output

Input # 1 copy

5 10
1 7
1 8
2 6
2 9
2 10
3 7
3 8
4 7
4 8
5 10
-1 -1

Output # 1 copy

4
1 7
2 9
3 8
5 10 

Ideas:

Maximum matching bipartite graph bare title, Hungary solution can be obtained, while the array output with the linker specific programs.

Or with solving the maximum flow,

The foreign pilots as dots on the left

British pilots as dots on the right,

That is a question about the biggest match between the points,

Then build a super source 0, and the source is connected to all the super-left point, the flow rate is 1.

Establishing a super sink n + 1, and the super sink all points on the right is connected to a flow.

Then connect the left and right side shall be subject to the possible side flow is also 1.

Then run the maximum flow, it is the best number matching scheme.

I ISAP algorithm is used to run the network flow.

If the intermediate side residual flow is zero, then the two sides of the node is a match in the matching scheme pair.

Network flow Code:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <vector>
#include <iomanip>
#define ALL(x) (x).begin(), (x).end()
#define sz(a) int(a.size())
#define rep(i,x,n) for(int i=x;i<n;i++)
#define repd(i,x,n) for(int i=x;i<=n;i++)
#define pii pair<int,int>
#define pll pair<long long ,long long>
#define gbtb ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define MS0(X) memset((X), 0, sizeof((X)))
#define MSC0(X) memset((X), '\0', sizeof((X)))
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define eps 1e-6
#define gg(x) getInt(&x)
#define chu(x) cout<<"["<<#x<<" "<<(x)<<"]"<<endl
#define du3(a,b,c) scanf("%d %d %d",&(a),&(b),&(c))
#define du2(a,b) scanf("%d %d",&(a),&(b))
#define du1(a) scanf("%d",&(a));
using namespace std;
typedef long long ll;
ll gcd(ll a, ll b) {return b ? gcd(b, a % b) : a;}
ll lcm(ll a, ll b) {return a / gcd(a, b) * b;}
ll powmod(ll a, ll b, ll MOD) {a %= MOD; if (a == 0ll) {return 0ll;} ll ans = 1; while (b) {if (b & 1) {ans = ans * a % MOD;} a = a * a % MOD; b >>= 1;} return ans;}
void Pv(const vector<int> &V) {int Len = sz(V); for (int i = 0; i < Len; ++i) {printf("%d", V[i] ); if (i != Len - 1) {printf(" ");} else {printf("\n");}}}
void Pvl(const vector<ll> &V) {int Len = sz(V); for (int i = 0; i < Len; ++i) {printf("%lld", V[i] ); if (i != Len - 1) {printf(" ");} else {printf("\n");}}}

inline void getInt(int* p);
const int maxn = 1000010;
const int inf = 0x3f3f3f3f;
/*** TEMPLATE CODE * * STARTS HERE ***/
#define N 1000
#define INF 100000000
struct Edge
{
    int from, to, cap, flow;
};

struct ISAP
{
    int n, m, s, t;
    vector<Edge>edges;
    vector<int>G[N];
    bool vis[N];
    int d[N], cur[N];
    int p[N], num[N]; //比Dinic算法多了这两个数组,p数组标记父亲结点,num数组标记距离d[i]存在几个
    void addedge(int from, int to, int cap)
    {
        edges.push_back((Edge) {from, to, cap, 0});
        edges.push_back((Edge) {to, from, 0, 0});
        int m = edges.size();
        G[from].push_back(m - 2);
        G[to].push_back(m - 1);
    }

    int Augumemt()
    {
        int x = t, a = INF;
        while (x != s) //找最小的残量值
        {
            Edge&e = edges[p[x]];
            a = min(a, e.cap - e.flow);
            x = edges[p[x]].from;
        }
        x = t;
        while (x != s) //增广
        {
            edges[p[x]].flow += a;
            edges[p[x] ^ 1].flow -= a;
            x = edges[p[x]].from;
        }
        return a;
    }
    void bfs()//逆向进行bfs
    {
        memset(vis, 0, sizeof(vis));
        queue<int>q;
        q.push(t);
        d[t] = 0;
        vis[t] = 1;
        while (!q.empty())
        {
            int x = q.front(); q.pop();
            int len = G[x].size();
            for (int i = 0; i < len; i++)
            {
                Edge&e = edges[G[x][i]];
                if (!vis[e.from] && e.cap > e.flow)
                {
                    vis[e.from] = 1;
                    d[e.from] = d[x] + 1;
                    q.push(e.from);
                }
            }
        }
    }

    int Maxflow(int s, int t) //根据情况前进或者后退,走到汇点时增广
    {
        this->s = s;
        this->t = t;
        int flow = 0;
        bfs();
        memset(num, 0, sizeof(num));
        for (int i = 0; i < n; i++)
            num[d[i]]++;
        int x = s;
        memset(cur, 0, sizeof(cur));
        while (d[s] < n)
        {
            if (x == t) //走到了汇点,进行增广
            {
                flow += Augumemt();
                x = s; //增广后回到源点
            }
            int ok = 0;
            for (int i = cur[x]; i < G[x].size(); i++)
            {
                Edge&e = edges[G[x][i]];
                if (e.cap > e.flow && d[x] == d[e.to] + 1)
                {
                    ok = 1;
                    p[e.to] = G[x][i]; //记录来的时候走的边,即父边
                    cur[x] = i;
                    x = e.to; //前进
                    break;
                }
            }
            if (!ok) //走不动了,撤退
            {
                int m = n - 1; //如果没有弧,那么m+1就是n,即d[i]=n
                for (int i = 0; i < G[x].size(); i++)
                {
                    Edge&e = edges[G[x][i]];
                    if (e.cap > e.flow)
                        m = min(m, d[e.to]);
                }
                if (--num[d[x]] == 0)break; //如果走不动了,且这个距离值原来只有一个,那么s-t不连通,这就是所谓的“gap优化”
                num[d[x] = m + 1]++;
                cur[x] = 0;
                if (x != s)
                    x = edges[p[x]].from; //退一步,沿着父边返回
            }
        }
        return flow;
    }
};
ISAP gao;
int n, m;

int main()
{
    //freopen("D:\\code\\text\\input.txt","r",stdin);
    //freopen("D:\\code\\text\\output.txt","w",stdout);
    du2(m, n);
    int x, y;
    while (~scanf("%d %d", &x, &y))
    {
        if (x + y == -2)
        {
            break;
        }
        gao.addedge(x, y, 1);
    }
    // gao.s = 0;
    // gao.t = n + 1;
    repd(i, 1, m)
    {
        gao.addedge(0, i, 1);
    }
    repd(i, m + 1, n)
    {
        gao.addedge(i, n + 1, 1);
    }
    gao.n = n + 2;
    printf("%d\n", gao.Maxflow(0, n + 1) );
    repd(i, 1, m)
    {
        for (auto yy : gao.G[i])
        {
            Edge temp =  gao.edges[yy];
            int v = temp.to;
            if (v > m && v <= n && temp.flow == 1)
            {
                printf("%d %d\n", i, v );
            }
        }
    }
    return 0;
}

inline void getInt(int* p) {
    char ch;
    do {
        ch = getchar();
    } while (ch == ' ' || ch == '\n');
    if (ch == '-') {
        *p = -(getchar() - '0');
        while ((ch = getchar()) >= '0' && ch <= '9') {
            *p = *p * 10 - ch + '0';
        }
    }
    else {
        *p = ch - '0';
        while ((ch = getchar()) >= '0' && ch <= '9') {
            *p = *p * 10 + ch - '0';
        }
    }
}


Hungary Code:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <vector>
#include <iomanip>
#define ALL(x) (x).begin(), (x).end()
#define sz(a) int(a.size())
#define rep(i,x,n) for(int i=x;i<n;i++)
#define repd(i,x,n) for(int i=x;i<=n;i++)
#define pii pair<int,int>
#define pll pair<long long ,long long>
#define gbtb ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define MS0(X) memset((X), 0, sizeof((X)))
#define MSC0(X) memset((X), '\0', sizeof((X)))
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define eps 1e-6
#define gg(x) getInt(&x)
#define chu(x) cout<<"["<<#x<<" "<<(x)<<"]"<<endl
#define du3(a,b,c) scanf("%d %d %d",&(a),&(b),&(c))
#define du2(a,b) scanf("%d %d",&(a),&(b))
#define du1(a) scanf("%d",&(a));
using namespace std;
typedef long long ll;
ll gcd(ll a, ll b) {return b ? gcd(b, a % b) : a;}
ll lcm(ll a, ll b) {return a / gcd(a, b) * b;}
ll powmod(ll a, ll b, ll MOD) {a %= MOD; if (a == 0ll) {return 0ll;} ll ans = 1; while (b) {if (b & 1) {ans = ans * a % MOD;} a = a * a % MOD; b >>= 1;} return ans;}
void Pv(const vector<int> &V) {int Len = sz(V); for (int i = 0; i < Len; ++i) {printf("%d", V[i] ); if (i != Len - 1) {printf(" ");} else {printf("\n");}}}
void Pvl(const vector<ll> &V) {int Len = sz(V); for (int i = 0; i < Len; ++i) {printf("%lld", V[i] ); if (i != Len - 1) {printf(" ");} else {printf("\n");}}}

inline void getInt(int* p);
const int maxn = 10010;
const int inf = 0x3f3f3f3f;
/*** TEMPLATE CODE * * STARTS HERE ***/
int linker[maxn * 2];
bool used[maxn * 2];
std::vector<int> son[maxn];
bool dfs(int u)
{

    for (auto v : son[u]) {
        if (!used[v]) {
            used[v] = true;
            if (linker[v] == -1 || dfs(linker[v])) {
                linker[v] = u;
                return true;
            }
        }
    }
    return false;
}

int n, m;
int hungarian()
{
    int res = 0;
    for (int i = 0; i <= n; i++) {
        linker[i] = -1;
    }
    for (int u = 1; u <= m; u++) {
        for (int i = 1; i <= n ; i++)
        {
            used[i] = 0;
        }// 根据题目判断是否改memset
        if (dfs(u))
        {
            res++;
        }
    }
    return res;
}
int main()
{
    //freopen("D:\\code\\text\\input.txt","r",stdin);
    //freopen("D:\\code\\text\\output.txt","w",stdout);
    du2(m, n);
    int x, y;
    while (~scanf("%d %d", &x, &y))
    {
        if (x + y == -2)
        {
            break;
        } else
        {
            son[x].push_back(y);
            son[y].push_back(x);
        }
    }
    cout << hungarian() << endl;
    repd(i, 1, n)
    {
        // chu(linker[i]);
        if (linker[i] != -1)
        {
            printf("%d %d\n", i, linker[i] );
        }
    }
    return 0;
}

inline void getInt(int* p) {
    char ch;
    do {
        ch = getchar();
    } while (ch == ' ' || ch == '\n');
    if (ch == '-') {
        *p = -(getchar() - '0');
        while ((ch = getchar()) >= '0' && ch <= '9') {
            *p = *p * 10 - ch + '0';
        }
    }
    else {
        *p = ch - '0';
        while ((ch = getchar()) >= '0' && ch <= '9') {
            *p = *p * 10 + ch - '0';
        }
    }
}


Guess you like

Origin www.cnblogs.com/qieqiemin/p/11627283.html