【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;
}

 

posted @ 2017-09-29 19:26  ssttkkl  阅读(620)  评论(0编辑  收藏  举报