bzoj 4950(二分图最大匹配)

来源:互联网 发布:js获取json对象 编辑:程序博客网 时间:2024/03/29 16:20

传送门
题意:求在不改变整个区域的三视图的前提下最多能拿走多少的箱子。
题解:(以下均在俯视的情况下)
对于每个有物品的格子,如果它有k个物品,最多能拿走k-1个。
显然只要留下每行每列最大值即可使三视图不变,于是将减多的补回来。然而这么操作有忽略了一个问题,题目说这个家伙可以重新安排物品位置,所以:如果i行,j列最大值相同,那么将只要交点处摆成最大值,其余的取得只剩1。就是说把多的补回来这一操作又补过了。如何让上述(i行,j列)交点处尽可能放最大值呢,行列建边跑个二分图最大匹配来求最大同时避免冲突(一个最大值只能放一次,即使有一行内两个格子都是最大值也只留一个,因为题目说要尽可能拿走!)

#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>using namespace std;typedef long long ll;const int MAXN=104;int n,m;bool vis[MAXN<<1];int mat[MAXN<<1];int a[MAXN][MAXN],r[MAXN],c[MAXN];int head[MAXN<<1],etot=0;struct EDGE {    int v,nxt;}e[MAXN*MAXN<<2];inline void adde(int u,int v) {    e[etot].nxt=head[u],e[etot].v=v,head[u]=etot++;    e[etot].nxt=head[v],e[etot].v=u,head[v]=etot++;}bool dfs(int p) {    for (int i=head[p];~i;i=e[i].nxt) {        int v=e[i].v;        if (!vis[v]) {            vis[v]=true;            if (mat[v]==-1||dfs(mat[v])) {                mat[v]=p;                return true;            }        }    }    return false;}int main() {//  freopen("bzoj 4950.in","r",stdin);    memset(head,-1,sizeof(head));    memset(mat,-1,sizeof(mat));    scanf("%d%d",&n,&m);    ll sum=0;    for (int i=1;i<=n;++i)        for (int j=1;j<=m;++j) {            scanf("%d",&a[i][j]);            r[i]=max(r[i],a[i][j]);            c[j]=max(c[j],a[i][j]);            if (a[i][j]) sum+=a[i][j]-1;        }    for (int i=1;i<=n;++i)        if (r[i]) sum-=r[i]-1;    for (int j=1;j<=m;++j)        if (c[j]) sum-=c[j]-1;    for (int i=1;i<=n;++i)        for (int j=1;j<=m;++j)            if (r[i]&&a[i][j]&&r[i]==c[j])                adde(i,j+n);    for (int i=1;i<=n;++i) {        memset(vis,false,sizeof(vis));        if (r[i]) sum+=dfs(i)*(r[i]-1);    }    printf("%lld\n",sum);    return 0;}
原创粉丝点击