bzoj4950 [Wf2017]Mission Improbable(二分图最大匹配)

一开始考虑,每个不为0的位置都拿到1,然后每行每列最大值不能动。然后又考虑到,如果行列最大值相同,我们可以在他们交叉的位置放一个最大值即可,而不需要两个。因此转化成一个二分图匹配的问题。(显然不同的最大值不会互相干扰,因为之间根本不可能有边)每成功匹配到一个,就可以多拿一个最大值。

#include 
using namespace std;
#define N 110
#define ll long long
#define inf 0x3f3f3f3f
#define eps 1e-9
inline int read(){
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    return x*f;
}
int n,m,a[N][N],mxn[N],mxm[N],boy[N];
ll ans=0;
bool f[N];
vector<int>e[N];
bool find(int x){
    for(int i=0;iint y=e[x][i];if(f[y]) continue;
        f[y]=1;if(!boy[y]||find(boy[y])){
            boy[y]=x;return 1;
        }
    }return 0;
}
int main(){
//  freopen("a.in","r",stdin);
    n=read();m=read();
    for(int i=1;i<=n;++i)
        for(int j=1;j<=m;++j){
            a[i][j]=read();if(a[i][j]) ans+=a[i][j]-1;
            mxn[i]=max(mxn[i],a[i][j]);mxm[j]=max(mxm[j],a[i][j]);
        }
    for(int i=1;i<=n;++i) if(mxn[i]) ans-=mxn[i]-1;//每行最大值不能拿走 
    for(int j=1;j<=m;++j) if(mxm[j]) ans-=mxm[j]-1;
    for(int i=1;i<=n;++i)
        for(int j=1;j<=m;++j)//行列最大相同,建边。 
            if(mxn[i]==mxm[j]&&a[i][j]) e[i].push_back(j);
    for(int i=1;i<=n;++i){
        memset(f,0,sizeof(f));if(find(i)) ans+=mxn[i]-1;//可以匹配,建一个就好了 
    }
    printf("%lld\n",ans);
    return 0;
}

你可能感兴趣的:(bzoj,二分图)