1. 程式人生 > >BZOJ_3996_[TJOI2015]線性代數_最大權閉合子圖

BZOJ_3996_[TJOI2015]線性代數_最大權閉合子圖

() NPU oid str AD while names content head

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

BZOJ_3996_[TJOI2015]線性代數_最大權閉合子圖