BZOJ_3996_[TJOI2015]线性代数_最大权闭合子图

BZOJ_3996_[TJOI2015]线性代数_最大权闭合子图

Description

给出一个N*N的矩阵B和一个1*N的矩阵C。求出一个1*N的01矩阵A.使得

D=(A*B-C)*A^T最大。其中A^T为A的转置。输出D

Input

第一行输入一个整数N,接下来N行输入B矩阵,第i行第J个数字代表Bij.
接下来一行输入N个整数,代表矩阵C。矩阵B和矩阵C中每个数字都是不超过1000的非负整数。

Output

输出最大的D

Sample Input

3
1 2 1
3 1 0
1 2 3
2 3 7

Sample Output

2

HINT

 1<=N<=500


根据乘法分配律可知,对于$b(i,j)$ ,只有$a[i],a[j]$ 都选才会有贡献。

而选择$a[j]$会导致选择$-c[j]$.

可以发现这是个最大权闭合子图的模型。

$S->b[i][j],b[i][j]->c[i],b[i][j]->c[j],c[i]->T$

 

代码:

#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
#define N 300050
#define M 2000050
#define inf 100000000
int head[N],to[M],nxt[M],flow[M],cnt=1,sum,n;
int dep[N],Q[N],l,r,S,T,idx[510][510],c[510];
inline void add(int u,int v,int f) {
    to[++cnt]=v; nxt[cnt]=head[u]; head[u]=cnt; flow[cnt]=f;
    to[++cnt]=u; nxt[cnt]=head[v]; head[v]=cnt; flow[cnt]=0;
}
bool bfs() {
    memset(dep,0,sizeof(dep));
    l=r=0;Q[r++]=S;dep[S]=1;
    while(l<r) {
        int x=Q[l++],i;
        for(i=head[x];i;i=nxt[i]) {
            if(!dep[to[i]]&&flow[i]) {
                dep[to[i]]=dep[x]+1;
                if(to[i]==T) return 1;
                Q[r++]=to[i];
            }
        }
    }
    return 0;
}
int dfs(int x,int mf) {
    if(x==T) return mf;
    int i,nf=0;
    for(i=head[x];i;i=nxt[i]) {
        if(dep[to[i]]==dep[x]+1&&flow[i]) {
            int tmp=dfs(to[i],min(mf-nf,flow[i]));
            if(!tmp) dep[to[i]]=0;
            nf+=tmp;
            flow[i]-=tmp;
            flow[i^1]+=tmp;
            if(nf==mf) break;
        }
    }
    return nf;
}
void dinic() {
    int f;
    while(bfs()) while(f=dfs(S,inf)) sum-=f;
    printf("%d\n",sum);
}
int main() {
    int i,j,x;
    scanf("%d",&n);
    S=n*n+n+1;T=S+1;
    int tot=0;
    for(i=1;i<=n;i++) {
        for(j=1;j<=n;j++) {
            idx[i][j]=++tot;
            scanf("%d",&x);
            sum+=x;
            add(S,tot,x);
        }
    }
    for(i=1;i<=n;i++) {
        scanf("%d",&c[i]);
        add(i+n*n,T,c[i]);
    }
    for(i=1;i<=n;i++) {
        for(j=1;j<=n;j++) {
            add(idx[i][j],n*n+i,inf);
            add(idx[i][j],n*n+j,inf);
        }
    }
    dinic();
}

 

posted @ 2018-05-06 14:29  fcwww  阅读(211)  评论(0编辑  收藏  举报