1. 程式人生 > >51nod. 2006 飛行員配對(二分圖最大匹配) (dinic)

51nod. 2006 飛行員配對(二分圖最大匹配) (dinic)

Problem Describe

第二次世界大戰時期,英國皇家空軍從淪陷國徵募了大量外籍飛行員。由皇家空軍派出的每一架飛機都需要配備在航行技能和語言上能互相配合的2名飛行員,其中1名是英國飛行員,另1名是外籍飛行員。在眾多的飛行員中,每一名外籍飛行員都可以與其他若干名英國飛行員很好地配合。如何選擇配對飛行的飛行員才能使一次派出最多的飛機。對於給定的外籍飛行員與英國飛行員的配合情況,試設計一個演算法找出最佳飛行員配對方案,使皇家空 軍一次能派出最多的飛機 。對於給定的外籍飛行員與英國飛行員的配合情況,程式設計找出一個最佳飛行員配對方案, 使皇家空軍一次能派出最多的飛機。

Input

第1行有2個正整數 m 和 n。n 是皇家空軍的飛行 員總數(n<100);m 是外籍飛行員數。外籍飛行員編號為 1~m;英國飛行員編號為 m+1~n。接下來每行有 2 個正整數 i 和 j,表示外籍飛行員 i 可以和英國飛行員 j 配合。輸入最後以 2 個-1 結束。

Output

第 1 行是最佳飛行 員配對方案一次能派出的最多的飛機數 M。如果所求的最佳飛行員配對方案不存在,則輸出‘No Solution!’。

Input示例

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示例

4

思路 :匈牙利演算法 或者 dinic演算法
dinic 學習報告
AC code:

dinic

#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

const int maxn = 110;

struct node{
    int nxt,to,w;
}edge[maxn*maxn];

int head[maxn] ,depth[maxn];
int
m ,n ,cnt ,u ,v ,source ,sink ; void init() { cnt = -1; memset( head, -1, sizeof(head)); } inline void add_edge(int u,int v,int w) { edge[++cnt].to = v; edge[cnt].w = w; edge[cnt].nxt = head[u]; head[u] = cnt; } int bfs() { queue<int>que; memset( depth, 0, sizeof(depth)); depth[source] = 1; que.push(source); while(!que.empty()) { int u = que.front(); que.pop(); for (int i = head[u]; ~i ; i = edge[i].nxt) { if ( edge[i].w > 0 && depth[edge[i].to] == 0 ) { depth[edge[i].to] = depth[u] + 1; que.push(edge[i].to); } } } return depth[sink] > 0; } int dfs(int u ,int dist ) { if ( u == sink ) return dist; for (int i = head[u]; ~i ;i = edge[i].nxt) { if ( depth[edge[i].to] == depth[u] + 1 && edge[i].w ) { int d = dfs(edge[i].to , min(dist ,edge[i].w )); if( d > 0) { edge[i].w -= d; edge[i^1].w += d; return d; } } } return 0; } int main() { init(); scanf("%d %d",&m,&n); source = 0 ,sink = n + 1 ; for (int i = 1;i <= m ;i++) add_edge(source ,i ,1 ) ,add_edge(i ,source ,0 ); for (int i = m + 1;i <= n;i++) add_edge(i ,sink ,1 ) ,add_edge(sink ,i ,0 ) ; while( ~scanf("%d %d",&u,&v) && (u != -1 && v != -1) ) { add_edge(u ,v ,1 ); add_edge(v ,u ,0 ); } int ans = 0 ; while(bfs()) { ans += dfs(source ,0x3f3f3f3f ); } if( ans == 0 ) printf("No Solution!\n"); else printf("%d\n",ans); return 0; }

匈牙利演算法

#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <iostream>

using namespace std;

const int MAXN = 105;
const int MAXE = 1e5 + 10;

struct edge
{
    int v;
    int nt;
};

int n, m;
int ans, tot;
int head[MAXN];
int match[MAXN];
bool flag[MAXN];
edge map[MAXE];

void add_edge(int x, int y)
{
    tot++;
    map[tot].v = y;
    map[tot].nt = head[x];
    head[x] = tot;
}

void init()
{
    memset(head, 0, sizeof(head));
    memset(match, 0, sizeof(match));

    ans = tot = 0;
}

bool dfs(int x)
{
    for (int e = head[x]; e; e = map[e].nt)
    {
        int v = map[e].v;
        if (!flag[v])
        {
            flag[v] = true;
            if (match[v] == 0 || dfs(match[v]))
            {
                match[v] = x;
                return true;
            }
        }
    }
    return false;
}

void hungary()
{
    for (int i = 1; i <= m; i++)
    {
        memset(flag, false, sizeof(flag));
        if (dfs(i))
        {
            ans++;
        }
    }
}

int main()
{
    init();

    scanf("%d%d", &m, &n);

    int x, y;
    while (scanf("%d%d", &x, &y), x != -1  &&  y != -1)
    {
        add_edge(x, y);
    }

    hungary();

    printf("%d\n", ans);

    return 0;
}

dinic + 當前弧優化

#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

const int maxn = 110;

struct node{
    int nxt,to,w;
}edge[maxn*maxn];

int head[maxn] ,depth[maxn] ,cur[maxn]; //cur陣列記錄當前弧
int m ,n ,cnt ,u ,v ,source ,sink ;

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

inline void add_edge(int u,int v,int w) {
    edge[++cnt].to = v;
    edge[cnt].w = w;
    edge[cnt].nxt = head[u];
    head[u] = cnt;
}

int bfs() {
    queue<int>que;
    memset( depth, 0, sizeof(depth));
    depth[source] = 1; que.push(source);
    while(!que.empty()) {
        int u = que.front(); que.pop();
        for (int i = head[u]; ~i ; i = edge[i].nxt) {
            if ( edge[i].w > 0 && depth[edge[i].to] == 0 ) {
                depth[edge[i].to] = depth[u] + 1;
                que.push(edge[i].to); 
            }
        }
    }
    return depth[sink] > 0;
}

int dfs(int u ,int dist ) {
    if ( u == sink ) return dist;
    for (int& i = cur[u]; ~i ;i = edge[i].nxt) { /!!!!/
        if ( depth[edge[i].to] == depth[u] + 1 && edge[i].w ) {
            int d = dfs(edge[i].to , min(dist ,edge[i].w ));
            if( d > 0) {
                edge[i].w -= d;
                edge[i^1].w += d;
                return d;
            }    
        }
    }
    return 0;
}

int main() {
    init();
    scanf("%d %d",&m,&n);
    source = 0 ,sink = n + 1 ;
    for (int i = 1;i <= m ;i++) add_edge(source ,i ,1 ) ,add_edge(i ,source ,0 );
    for (int i = m + 1;i <= n;i++) add_edge(i ,sink ,1 ) ,add_edge(sink ,i ,0 ) ; 
    while( ~scanf("%d %d",&u,&v) && (u != -1 && v != -1) ) {
        add_edge(u ,v ,1 );
        add_edge(v ,u ,0 );
    }
    int ans = 0 ;
    while(bfs()) {
        for (int i = 0;i<=n+1;i++) cur[i] = head[i]; // 更改當前弧
        ans += dfs(source ,0x3f3f3f3f );
    }
    if( ans == 0 ) printf("No Solution!\n");
    else printf("%d\n",ans);
    return 0;
}