题目要求
ans=Maximize∑i=1NA1,i⋅⎛⎝∑j=1NA1,j⋅Bi,j−C1,i⎞⎠
方法一
直接推到最小割
因为目标函数最大化,所以先将其转为最小化
令
sum=∑i=1N∑j=1NBi,j
cost=∑i=1NA1,i⋅⎛⎝∑j=1N(1−A1,j)⋅Bi,j+Ci⎞⎠+∑i=1N(1−A1,i)⋅∑j=1NBi,j
则
ans=tot−Minimize(cost)
方法二
最大权闭合子图
一个
Bi,j
被加入答案,那么
A1,i
与
A1,j
必须都是
1
,在图中可以看做点
一个
C1,i
被答案减去,
A1,i
必须是
1
,在图中可以看做
于是我们得到了一个有向图,图中的每个
Bi,j
都由两个点
A1,i
与
A1,j
指向.
每个
A
点的点权为
然后裸最大权闭合子图辣
/****************************************\
* Author : ztx
* Title : [bzoj] 3996 [TJOI2015]线性代数
* ALG : 嘛,最小割大水题,但是把它想成最大权闭合子图就太高达上了QAQ
* CMT :
* Time :
\****************************************/
#include <cstdio>
#define Rep(i,l,r) for(i=(l);i<=(r);i++)
#define rep(i,l,r) for(i=(l);i< (r);i++)
#define Rev(i,r,l) for(i=(r);i>=(l);i--)
#define rev(i,r,l) for(i=(r);i> (l);i--)
typedef long long ll ;
int CH , NEG ;
template <typename TP>inline void read(TP& ret) {
ret = NEG = 0 ; while (CH=getchar() , CH<'!') ;
if (CH == '-') NEG = true , CH = getchar() ;
while (ret = ret*10+CH-'0' , CH=getchar() , CH>'!') ;
if (NEG) ret = -ret ;
}
template <typename TP>inline void readc(TP& ret) {
while (ret=getchar() , ret<'!') ;
while (CH=getchar() , CH>'!') ;
}
template <typename TP>inline void reads(TP *ret) {
ret[0]=0;while (CH=getchar() , CH<'!') ;
while (ret[++ret[0]]=CH,CH=getchar(),CH>'!') ;
ret[ret[0]+1]=0;
}
#define maxN 300010LL
#define maxM 900010LL
#define infi 0x7f7f7f7fLL
#define min(x,y) ((x)<(y)?(x):(y))
struct FST { int to,next,flow; } e[maxM<<1] ;
int star[maxN] = {0} , tote = 1 ;
inline void AddEdge(int u,int v,int cap) {
e[++tote].to=v;e[tote].flow=cap;e[tote].next=star[u];star[u]=tote;
e[++tote].to=u;e[tote].flow=0;e[tote].next=star[v];star[v]=tote;
}
int n , S , T , N ;
int h[maxN] = {0} , vh[maxN] = {0} ;
int dfs(int u,int flowu) {
int p , tmp = h[u]+1 ;
int flow = 0 , flowv ;
if (u == T) return flowu ;
for (p = star[u] ; p ; p = e[p].next)
if (e[p].flow>0 && h[u]==h[e[p].to]+1) {
flowv = dfs(e[p].to,min(e[p].flow,flowu-flow)) ;
flow += flowv ; e[p].flow -= flowv , e[p^1].flow += flowv ;
if (h[S]==N || flow==flowu) return flow ;
}
for (p=star[u] ; p ; p=e[p].next)
if (e[p].flow>0 && h[e[p].to]<tmp) tmp = h[e[p].to] ;
if (--vh[h[u]] == 0) h[S] = N ;
else ++vh[h[u]=tmp+1] ;
return flow ;
}
inline int SAP() {
int ret = 0 ;
vh[0] = N ;
while (h[S] < N) ret += dfs(S,infi) ;
return ret ;
}
inline int A(int i) { return n*n+i ; }
inline int B(int i,int j) { return (i-1)*n+j ; }
int main() {
int i , j , w , ans ;
#define READ
#ifdef READ
freopen("data.in" ,"r",stdin ) ;
freopen("data.out","w",stdout) ;
#endif
read(n) ;
S = n*n+n+1 , T = N = S+1 ;
ans = 0 ;
Rep (i,1,n) Rep (j,1,n) {
read(w) ;
ans += w ;
AddEdge(B(i,j),T,w) ;
AddEdge(A(i),B(i,j),infi) ;
AddEdge(A(j),B(i,j),infi) ;
}
Rep (i,1,n) {
read(w) ;
AddEdge(S,A(i),w) ;
}
ans -= SAP() ;
printf("%d\n", ans) ;
#ifdef READ
fclose(stdin) ; fclose(stdout) ;
#else
getchar() ; getchar() ;
#endif
return 0 ;
}