bzoj4950

这题思路真的挺巧妙的,很难想到二分图匹配

  对于俯视图,我们使有箱子的格子不被拿完即可。对于侧视图和正视图,使行和列的最大值保持不变即可。
  注意到某一行和某一列的最大值可能相同,对此,我们将尽量保留这样的最大值。
  将最大值相等的行和列连边,跑一遍二分图最大匹配即可。
 
#include<cstdio>
#include<cctype>
#include<algorithm>
#include<vector>
#include<cstring>
int n,m,mxn[102],mxm[102],match[102],map[102][102];
long long ans;
bool vis[102];
std::vector<int>G[102];
inline void read(int &x){
    char ch=getchar();x=0;int f=1;
    while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    while(isdigit(ch)){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
    x*=f;
}
inline bool dfs(int u){
    for(int i=0;i<G[u].size();i++){
        int v=G[u][i];
        if(vis[v]==1)continue;
        vis[v]=1;
        if(match[v]==0 || dfs(match[v])){
            match[v]=u;return true;
        }
    }
    return false;
}
int main(){
    read(n);read(m);
    for(int i=1;i<=n;i++)
       for(int j=1;j<=m;j++){
           read(map[i][j]);
           if(map[i][j]>0){
               ans+=1LL*(map[i][j]-1);
               mxn[i]=std::max(map[i][j],mxn[i]);mxm[j]=std::max(map[i][j],mxm[j]);
           }
       }
    for(int i=1;i<=n;i++)if(mxn[i])ans-=1LL*(mxn[i]-1);for(int i=1;i<=m;i++)if(mxm[i])ans-=1LL*(mxm[i]-1);
    for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)if(map[i][j] && mxn[i] && mxn[i]==mxm[j])G[i].push_back(j);
    for(int i=1;i<=n;i++){memset(vis,0,sizeof vis);if(mxn[i]>0 && dfs(i))ans+=1LL*(mxn[i]-1);}
    printf("%lld",ans);
    return 0;
}

 

posted @ 2018-06-13 07:26  lnyzo  阅读(72)  评论(0编辑  收藏  举报