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