• 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!
    ");
        else printf("%d
    ",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
    ", 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!
    ");
        else printf("%d
    ",ans);
        return 0;
    }
  • 相关阅读:
    C#开源资源大汇总
    未来IT人才市场最热门的12项技能
    C#中使用ROT13加密解密
    SphinX人像识别 联想笔记本人脸识别系统 (适合所有带摄像头的电脑)
    关于电脑的困惑,请各位大哥给个指点
    用Cacls修改文件访问控制权限
    2008年国外最佳Web设计/开发技巧、脚本及资源总结
    mysql密码设置
    MySQL常规练习 .MySQL安装成功后的进入方式
    JSTL包
  • 原文地址:https://www.cnblogs.com/Nlifea/p/11745944.html
Copyright © 2020-2023  润新知