• 二分图最大权完美匹配


    洛谷P6577二分图最大权完美匹配(50分)后需bfs优化

    因为边权取值可以为负,所以开始初始化为-INF;

    ans为ll,km函数返回值为ll;

    板子1:

    #include <bits/stdc++.h>
    using namespace std;
    const int maxn = 555;
    const int INF = 0x3f3f3f3f;
    typedef long long ll;
    int val[maxn][maxn], vis_A[maxn], vis_B[maxn], match[maxn];     //vis来记录已被匹配的,match记录B方匹配到了A方的哪个
    int ex_A[maxn], ex_B[maxn], slack[maxn], m, n, e;                        //记录A方和B方的期望, A方有m个,B方有n个
    //slack 任意一个参与匹配A方能换到任意一个这轮没有被选择过的B方所需要降低的最小值
    //这是二分图的最优匹配(首先是A集合的完备匹配,然后保证权值最大)
    //所以一定保证 m <= n, 否则会陷入死循环,若是A集合点多的话可以把B集合补充到和A一样多,设置-INF的边
    bool dfs(int x)
    {
        vis_A[x] = 1;
        for(int i = 1; i <= n; i++)
        {
            if(!vis_B[i])                             //每一轮匹配,B方每一个点只匹配一次
            {
                int gap = ex_A[x] + ex_B[i] - val[x][i];
                if(gap == 0)                         //如果符合要求
                {
                    vis_B[i] = 1;
                    if(!match[i] || dfs(match[i]))   //如果v尚未匹配或者匹配了可以被挪走
                    {
                        match[i] = x;
                        return true;
                    }
                }
                else slack[i] = min(slack[i], gap);
            }
        }
        return false;
    }
    
    ll km()
    {
        memset(match, 0, sizeof(match));            //match为0表示还没有匹配
        fill(ex_B + 1, ex_B + 1 + n, 0);             //B方一开始期望初始化为0
        for(int i = 1; i <= m; i++)                 //A方期望取最大值
        {
            ex_A[i] = val[i][1];
            for(int j = 2; j <= n; j++)
                ex_A[i] = max(ex_A[i], val[i][j]);
        }
        for(int i = 1; i <= m; i++)               //尝试解决A方的每一个节点
        {
            memset(slack + 1, INF, sizeof(slack[0]) * n);
            for(;;)
            {
                memset(vis_A + 1, 0, sizeof(vis_A[0]) * m);     //记录AB双方有无被匹配过
                memset(vis_B + 1, 0, sizeof(vis_B[0]) * n);
                if(dfs(i))  break;
                int d = INF;
                for(int j = 1; j <= n; j++)    if(!vis_B[j]) d = min(d, slack[j]);
                //if(d == INF)  break;                        //找不到完全匹配
                for(int j = 1; j <= m; j++) if(vis_A[j]) ex_A[j] -= d;
                for(int j = 1; j <= n; j++)
                {
                    if(vis_B[j]) ex_B[j] += d;
                    else slack[j] -= d;
                }
            }
        }
        ll ans = 0;
        for(int i = 1; i <= n; i++)
        {
            if(match[i])              // 可以加 && val[match[i]][i] > -INF 去除一些匹配
                ans += val[match[i]][i];
        }
        return ans;
    }
    
    int main()
    {
        scanf("%d %d", &n, &e);
        int x, y, w;
        m = n;
        for(int i = 1; i <= n; ++i)
            for(int j = 1; j <= n; ++j)
                val[i][j] = -INF;
        for(int i = 1; i <= e; ++i)
        {
            scanf("%d %d %d", &x, &y, &w);
            val[x][y] = w;
        }
        cout << km() << endl;
        for(int i = 1; i <= n; ++i)
            if(match[i]) printf("%d ", match[i]);
    }

    板子2:

    #include <bits/stdc++.h>
    using namespace std;
    const int maxn = 555;
    const int INF = 0x3f3f3f3f;
    typedef long long ll;
    int val[maxn][maxn], vis_a[maxn], vis_b[maxn], match[maxn];
    int ex_a[maxn], ex_b[maxn], n, m, e;
    
    bool dfs(int x)
    {
        vis_a[x] = 1;
        for(int i = 1; i <= m; ++i)
        {
            if(!vis_b[i] && ex_a[x] + ex_b[i] == val[x][i])
            {
                vis_b[i] = 1;
                if(!match[i] || dfs(match[i]))
                {
                    match[i] = x;
                    return 1;
                }
            }
        }
        return 0;
    }
    
    ll km()
    {
        memset(match, 0, sizeof(match));
        fill(ex_b + 1, ex_b + 1 + n, 0);
        for(int i = 1; i <= n; ++i)
        {
            ex_a[i] = val[i][1];
            for(int j = 2; j <= m; ++j)
                ex_a[i] = max(ex_a[i], val[i][j]);
        }
        for(int i = 1; i <= m; ++i)
        {
            while(1)
            {
                memset(vis_a + 1, 0, sizeof(vis_a[0]) * n);
                memset(vis_b + 1, 0, sizeof(vis_b[0]) * m);
                if(dfs(i)) break;
                int d = INF;
                for(int j = 1; j <= n; ++j)
                    if(vis_a[j])
                        for(int k = 1; k <= m; ++k)
                            if(!vis_b[k]) d = min(d, ex_a[j] + ex_b[k] - val[j][k]);
                for(int j = 1; j <= n; ++j) if(vis_a[j]) ex_a[j] -= d;
                for(int j = 1; j <= m; ++j) if(vis_b[j]) ex_b[j] += d;
            }
        }
        ll ans = 0;
        for(int i = 1; i <= n; ++i)
        {
            if(match[i]) ans += val[match[i]][i];
        }
        return ans;
    }
    
    int main()
    {
        scanf("%d %d", &n, &e);
        int x, y, w;
        m = n;
        for(int i = 1; i <= n; ++i)
            for(int j = 1; j <= n; ++j)
                val[i][j] = -INF;
        for(int i = 1; i <= e; ++i)
        {
            scanf("%d %d %d", &x, &y, &w);
            val[x][y] = w;
        }
        cout << km() << endl;
        for(int i = 1; i <= n; ++i)
            if(match[i]) printf("%d ", match[i]);
    }
  • 相关阅读:
    网络爬虫之Cookies解决
    高性能异步爬虫
    Python csv存储
    pandas ExcelWriter用法及代码示例
    pandas to_excel 用法详解
    pandas read_csv 与 to_csv 方法各参数详解
    pandas read_excel操作
    pandas DataFrame.groupby()所见的各种用法详解
    Pandas 中 DataFrame 基本函数整理
    Python 解析二维码 输出文本
  • 原文地址:https://www.cnblogs.com/Maxx-el/p/14095084.html
Copyright © 2020-2023  润新知