考虑把柿子展开,发现会变成
∑
i
=
1
n
∑
j
=
1
n
A
i
∗
A
j
∗
B
i
,
j
−
∑
i
=
1
n
A
i
∗
C
i
\sum_{i=1}^n \sum_{j=1}^n A_i*A_j*B_{i,j}-\sum_{i=1}^n A_i*C_i
i=1∑nj=1∑nAi∗Aj∗Bi,j−i=1∑nAi∗Ci
那么也就是说,如果
A
i
,
A
j
A_i, A_j
Ai,Aj同时为1,那么就会有
B
i
,
j
B_{i,j}
Bi,j的收益,但是让单个
A
i
A_i
Ai为1会有
C
i
C_i
Ci的花费,然后跑一个收益-花费的网络流即可
每次先加上所有的收益,然后
S
S
S向
n
∗
n
n*n
n∗n个点连收益,剩下
n
n
n个点向
T
T
T连花费,然后跑网络流,减去此时的最小割即可
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
int const N = 260000;
int const M = N * 10;
int const inf = 10000000;
struct ISAP {
struct Edge {
int y,f,next;
}e[M];
int last[N],ne;
int d[N],cur[N],pre[N],num[N];
int S,T,nv;
void init(int _n) {
S=_n+1; T=_n+2;
nv=T+1;
ne=0;
memset(last,-1,sizeof(last));
}
void add(int x,int y,int f) {
e[ne].y=y; e[ne].f=f; e[ne].next=last[x]; last[x]=ne; ne++;
}
void link(int x,int y,int f) {
add(x,y,f);
add(y,x,0);
}
void rev_bfs() {
memset(num,0,sizeof(num));
memset(d,-1,sizeof(d));
d[T]=0;
num[0]=1;
queue<int> Q;
while(!Q.empty()) Q.pop();
Q.push(T);
while(!Q.empty()) {
int x=Q.front(); Q.pop();
for(int i=last[x];~i;i=e[i].next) {
int y=e[i].y;
if(~d[y]) continue;
d[y]=d[x]+1;
num[d[y]]++;
Q.push(y);
}
}
}
int solve() {
memset(pre,0,sizeof(pre));
memcpy(cur,last,sizeof(cur));
rev_bfs();
if(d[S]==-1) return 0; ///不联通
int ret=0;
int u=pre[S]=S,i;
while(d[T]<nv) {
if(u==T) {
int f=inf;
int neck;
for(i=S;i!=T;i=e[cur[i]].y) {
if(f>e[cur[i]].f) {
f=e[cur[i]].f;
neck=i;
}
}
for(i=S;i!=T;i=e[cur[i]].y) {
e[cur[i]].f-=f;
e[cur[i]^1].f+=f;
}
ret+=f;
u=neck;
}
for(i=cur[u];~i;i=e[i].next) if(d[e[i].y]+1==d[u] && e[i].f) break;
if(~i) {
cur[u]=i;
pre[e[i].y]=u;
u=e[i].y;
} else {
if(0== (--num[d[u]])) break;
int mind=nv;
for(i=last[u];~i;i=e[i].next) {
if(e[i].f && mind>d[e[i].y]) {
cur[u]=i;
mind=d[e[i].y];
}
}
d[u]=mind+1;
num[d[u]]++;
u=pre[u];
}
}
return ret;
}
} isap;
int b[501][501];
int c[501];
int n;
int main() {
ios::sync_with_stdio(0);
cin >> n;
isap.init(n * n + n);
ll ans = 0;
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= n; ++j) {
cin >> b[i][j];
ans += b[i][j];
int now = (i - 1) * n + j;
isap.link(isap.S, now, b[i][j]);
isap.link(now, n * n + i, inf);
isap.link(now, n * n + j, inf);
}
for (int i = 1; i <= n; ++i) {
cin >> c[i];
isap.link(n * n + i, isap.T, c[i]);
}
cout << ans - isap.solve() << '\n';
}