如果
ai=1
,那么
B
的第
如果
ai=0
,那么什么都不会发生。
如果
ai=0
且
aj=1
,那么之前的
B
的第
将包含源点的集合作为
ai=0
的集合,将包含汇点的集合作为
ai=1
的集合,按照上述关系建图求最小割即可(需要转换一下关系)。
因为边数比较大,用sap需要开一下gap外挂。
#include<algorithm>
#include<iostream>
#include<cstring>
#include<climits>
#include<cstdio>
using namespace std;
#define clr(a) memset(a,0,sizeof(a))
typedef long long ll;
const int up=INT_MAX;
struct eg{
int u,v,nx,c;
}gp[5000010];
int cnt,hd[3010],sn;
void _psh(int u,int v,int c){
++cnt;
gp[cnt].u=u,gp[cnt].v=v,gp[cnt].c=c;
gp[cnt].nx=hd[u],hd[u]=cnt;
};
inline void psh(int u,int v,int c){
_psh(u,v,c);_psh(v,u,0);
};
int eg[3010],pi[3010],gap[3010],ds[3010];
int sap(){
int r=0,i,t,ic=up,v=0;bool fg;
clr(gap),clr(ds);
for(i=0;i<=sn;++i)eg[i]=hd[i];
while(ds[0]!=sn+1){
if(v==sn){
r+=ic;
for(;v;v=gp[pi[v]].u){
gp[pi[v]].c-=ic;
gp[pi[v]&1?pi[v]+1:pi[v]-1].c+=ic;
}
ic=up;
}
for(fg=0,i=eg[v];i&&!fg;i=gp[i].nx){
if(gp[i].c&&ds[gp[i].v]+1==ds[v]){
fg=1;
pi[gp[i].v]=i;
eg[v]=i;
ic=min(ic,gp[i].c);
v=gp[i].v;
}
}
if(fg)continue;
--gap[ds[v]];
if(gap[ds[v]]==0)ds[0]=sn+1;
for(t=up,i=hd[v];i;i=gp[i].nx){
if(gp[i].c&&ds[gp[i].v]!=sn+1)
t=min(t,ds[gp[i].v]);
}
ds[v]=t<up?t+1:sn+1;
gap[ds[v]]++;
eg[v]=hd[v];
v=v?gp[pi[v]].u:0;
}
return r;
};
int n;
int br[1010][1010],cr[1010];
int sr[1010];
void cl(){
int i,j,k,sm;scanf("%d",&n);
for(i=1,sm=0;i<=n;++i){
sr[i]=0;
for(j=1;j<=n;++j){
scanf("%d",&br[i][j]);
sr[i]+=br[i][j];
}
sm+=sr[i];
}
for(i=1;i<=n;++i)scanf("%d",&cr[i]);
clr(hd),cnt=0,sn=n+1;
for(i=1;i<=n;++i){
psh(0,i,cr[i]);
psh(i,sn,sr[i]);
for(j=1;j<=n;++j){
if(i!=j){
psh(i,j,br[j][i]);
}
}
}
printf("%d\n",sm-sap());
};
int main(){
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
#endif
int t;scanf("%d",&t);
while(t--)cl();
return 0;
};