51nod. 2006 飞行员配对(二分图最大匹配) (dinic)

版权声明:博主的文章,请随意转载 https://blog.csdn.net/Acer12138/article/details/82620219

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;
}

猜你喜欢

转载自blog.csdn.net/Acer12138/article/details/82620219