BZOJ4950 Wf2017Mission Improbable(二分图匹配)
先给每个非零格子-1以满足俯视图不变。于是就相当于要求每行每列最大值不变。能减少剩余箱子的唯一方法是在要求相同的行列的交叉处放箱子以同时满足两个需求。给这些行列连边跑二分图匹配即可。注意必须格子初始时有箱子才能放在这。
#include<iostream> #include<cstdio> #include<cmath> #include<cstdlib> #include<cstring> #include<algorithm> using namespace std; #define ll long long #define N 110 char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;} int gcd(int n,int m){return m==0?n:gcd(m,n%m);} int read() { int x=0,f=1;char c=getchar(); while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();} while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar(); return x*f; } int n,m,a[N][N],r[N],c[N],p[N<<1],match[N<<1],flag[N<<1],t; ll tot; struct data{int to,nxt; }edge[N*N<<1]; void addedge(int x,int y){t++;edge[t].to=y,edge[t].nxt=p[x],p[x]=t;} bool hungary(int k,int f) { for (int i=p[k];i;i=edge[i].nxt) if (flag[edge[i].to]!=f) { flag[edge[i].to]=f; if (!match[edge[i].to]||hungary(match[edge[i].to],f)) { match[edge[i].to]=k; return 1; } } return 0; } int main() { #ifndef ONLINE_JUDGE freopen("bzoj4950.in","r",stdin); freopen("bzoj4950.out","w",stdout); const char LL[]="%I64d\n"; #else const char LL[]="%lld\n"; #endif n=read(),m=read(); for (int i=1;i<=n;i++) for (int j=1;j<=m;j++) { a[i][j]=read(); int x=max(a[i][j]-1,0); tot+=x,r[i]=max(r[i],x),c[j]=max(c[j],x); } for (int i=1;i<=n;i++) tot-=r[i]; for (int i=1;i<=m;i++) tot-=c[i]; for (int i=1;i<=n;i++) for (int j=1;j<=m;j++) if (r[i]==c[j]&&a[i][j]) addedge(i,j+n); for (int i=1;i<=n;i++) hungary(i,i); for (int i=1;i<=m;i++) if (match[n+i]) tot+=c[i]; cout<<tot; return 0; }