zoukankan      html  css  js  c++  java
  • 【WF2017】Mission Improbable

    http://www.lydsy.com/JudgeOnline/problem.php?id=4950

    对于俯视图很好解决,把所有不是0的位置拿到剩1就可以了。

    对于正视图与侧视图,稍微想一下也能发现只要保持每行(和每列)箱子最多的那个位置不动就可以了。

    但是可能存在一行有两个以上的点都是最大值,并且其中一点所在的列的最大值也和这行的最大值相等的情况。这时候只保持这一点不变,显然优于同时保持该行另一点和那一列的最大值那点不变要更优。

    这时候就可以建二分图找最大匹配了:将若i行与j列的最大值相等且不为零,且(i,j)原本有箱子,就在i与r+j连边。

    最后统计一下答案就可以了。

    #include <iostream>
    #include <cstring> 
    #define maxn 105
    using namespace std;
    int r, c, grid[maxn][maxn];
    int rmax[maxn], cmax[maxn];
    struct
    {
        int to, next;
    } edges[maxn * maxn];
    int head[maxn * 2];
    void addedge(int u, int v)
    {
        static int ecnt = 1;
        edges[ecnt].to = v;
        edges[ecnt].next = head[u];
        head[u] = ecnt++;
    }
    bool vis[maxn * 2];
    int mat[maxn * 2];
    bool dfs(int v)
    {
        for (int i = head[v]; i; i = edges[i].next)
        {
            int w = edges[i].to;
            if (!vis[w])
            {
                vis[w] = true;
                if (!mat[w] || dfs(mat[w]))
                {
                    mat[w] = v;
                    mat[v] = w;
                    return true;
                }
            }
        }
        return false;
    }
    void hungary()
    {
        for (int i = 1; i <= r; i++)
        {
            if (!mat[i])
            {
                memset(vis, false, sizeof(vis));
                dfs(i);
            }
        }
    }
    
    int main()
    {
        ios::sync_with_stdio(false);
        unsigned long long ans = 0;
        cin >> r >> c;
        for (int i = 1; i <= r; i++)
        {
            for (int j = 1; j <= c; j++)
            {
                cin >> grid[i][j];
                if (grid[i][j])
                {
                    rmax[i] = max(rmax[i], grid[i][j]);
                    cmax[j] = max(cmax[j], grid[i][j]);
                    ans += grid[i][j] - 1;
                }
            }
        }
    
        // 若i行与j列的最大值相同,就可以把位置(i,j)放上这个最大值的数量的箱子,然后将i行与j列的其他能偷的箱子全部偷走
        // 但是若(i,j)原来是0,这个位置就不能放箱子了
        for (int i = 1; i <= r; i++)
            for (int j = 1; j <= c; j++)
                if (rmax[i] == cmax[j] && rmax[i] && grid[i][j])
                    addedge(i, j + maxn);
        hungary();
     
        for (int i = 1; i <= r; i++)
            if (rmax[i])
                ans -= rmax[i] - 1;
        for (int i = 1; i <= c; i++)
            if (!mat[i + maxn] && cmax[i])
                ans -= cmax[i] - 1;
        cout << ans;
        return 0;
    }
  • 相关阅读:
    Postman+Newman+jenkins实现API自动化测试
    抓包,反抓包,反反抓包
    使用Magisk+riru实现全局改机
    stat命令的实现-mysate(必做)
    第五章学习笔记
    第四章学习笔记
    2.3.1测试
    缓冲区溢出
    学习笔记6
    电子公文传输系统团队项目——需求规格说明书
  • 原文地址:https://www.cnblogs.com/ssttkkl/p/7612494.html
Copyright © 2011-2022 走看看