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;
    }
  • 相关阅读:
    (转)if __name__ == '__main__' 如何正确理解?
    (转)Django配置mysql数据库
    (转)Python虚拟环境pyenv、venv(pyvenv)、virtualenv之间的区别,终于搞清楚了!
    找出Framework 4.0 新增的方法和新增的类(下)
    C# MBG 扩展方法类库 分享
    是技术还是态度,网易的视频Title
    不要返回null之EmptyFactory
    你知道这段代码的输出吗?
    C# 4.0 大数的运算,BigInteger
    CleanCode: 面向过程 PK 面向对象
  • 原文地址:https://www.cnblogs.com/ssttkkl/p/7612494.html
Copyright © 2011-2022 走看看