• 2016级算法期末上机-H.难题·AlvinZH's Fight with DDLs III


    1119 AlvinZH's Fight with DDLs III

    思路

    难题,最小点覆盖。

    分析题意,某一个任务,既可以在笔记本A的 (a) 模式下完成,也可以在笔记本B的 (b) 模式下完成。如果笔记本A处于x模式,那么所有可以在笔记本x模式的任务可以一起完成,B同理。这两句话作为题目核心,该如何转化呢?

    对于每个任务对应的(a,b),我们把它映射到平面坐标当中,明显发现,此题和二营长,你他娘的意大利炮呢简直一模一样。其实就是一个最小点覆盖问题,也就是最大二分图匹配问题。

    关于最小点覆盖问题为什么等价于最大二分图匹配,第五次讲解课上有证明,期末练习赛E题难题·AlvinZH的青春记忆III大家也遇到过,不知道你真的好好练习了吗?

    采用经典的匈牙利算法,构建图时需要注意,由于笔记本AB最初都处于模式0,也就是说若a或b等于0,这个任务可以直接忽略。

    分析

    二分图匹配算法

    1.匈牙利算法:其本质就是,有条件就上,没条件创造条件也要上。DFS与BFS都可,时间复杂度均为 (O(V⋅E)) 。实际对于稀疏图BFS更佳。

    2.Hopcroft-Karp算法:匈牙利算法的改进版,每次寻找多条增广路径。时间复杂度可以到达 (O(n^{0.5}*m))

    3.Dinic算法:二分图匹配其实是一个最大流问题,Dinic是一种优化过的求解最大流算法。与朴素的FF算法((O(n*m^2)))不同,其可以同时多路增广。求解二分图时,构建超级源点和超级汇点,匹配边权值为1,求最大流即可。理论最坏复杂度为 (O(n^2m)) ,稠密图时比匈牙利DFS快了不少。

    参考博客:二分图;
    匈牙利算法;
    Hopcroft-Karp算法;
    Dinic算法

    参考代码

    /* 
     Author: 朱辉(35)
     Result: AC	Submission_id: 514523
     Created at: Mon Dec 25 2017 00:33:21 GMT+0800 (CST)
     Problem: 1119	Time: 82	Memory: 3024
    */
    
    #include <cstdio>
    #include <cstring>
    #include <vector>
    #define MaxSize 10005
    using namespace std;
    
    int n, m, k;
    vector<int> G[MaxSize];//邻接矩阵
    int match[MaxSize];//记录匹配点
    int visit[MaxSize];//记录是否访问
    
    bool dfs(int x)//寻找增广路径
    {
        for (int i = 0; i < G[x].size(); ++i)
        {
            int to = G[x][i];
            if(!visit[to])
            {
                visit[to] = 1;
                if(!match[to] || dfs(match[to]))
                {
                    match[to] = x;
                    return true;
                }
            }
        }
        return false;
    }
    
    int MaxMatch()
    {
        int ans = 0;
        memset(match, 0, sizeof(match));
        for (int i = 1; i <= n-1; ++i)
        {
            memset(visit, 0, sizeof(visit));//清空访问
            if(dfs(i)) ans++;//从节点i尝试扩展
        }
        return ans;
    }
    
    int main()
    {
        while(~scanf("%d %d %d", &n, &m, &k))
        {
            for (int i = 0; i <= n; ++i)
                G[i].clear();
    
            int a, b;
            for (int i = 1; i <= k; ++i) {
                scanf("%d %d", &a, &b);
                if(a*b != 0)
                    G[a].push_back(b);
            }
    
            printf("%d
    ", MaxMatch());
        }
    }
    
  • 相关阅读:
    设计模式 : Template method 模板方法模式 -- 行为型
    设计模式:Strategy 策略模式 -- 行为型
    没有评审的技术都是扯淡
    TCP/IP 协议大致的概念
    HTTP 2.0 与 tomcat
    相对URL拼接为绝对URL的过程
    URI与URL区别
    《淘宝首页性能优化实践》文章阅读
    第一章 Linux内核简介
    vim中执行shell命令小结
  • 原文地址:https://www.cnblogs.com/AlvinZH/p/8215925.html
Copyright © 2020-2023  润新知