==线代好难
#include<stdio.h>
#include<string.h>
#include<iostream>
#include<math.h>
#include<algorithm>
#include<queue>
#include<vector>
template <class T>
inline bool rd(T &ret) {
char c; int sgn;
if(c=getchar(),c==EOF) return 0;
while(c!='-'&&(c<'0'||c>'9')) c=getchar();
sgn=(c=='-')?-1:1;
ret=(c=='-')?0:(c-'0');
while(c=getchar(),c>='0'&&c<='9') ret=ret*10+(c-'0');
ret*=sgn;
return 1;
}
template <class T>
inline void pt(T x) {
if (x <0) {
putchar('-');
x = -x;
}
if(x>9) pt(x/10);
putchar(x%10+'0');
}
typedef int ll;
const int N = 1005;
const int M = N*N + 2*N;
const int inf = 107374182;
const long long inf64 = 1e18;
using namespace std;
struct Edge{
int from, to;
ll cap; int nex;
}edge[M*2];//注意这个一定要够大 不然会re 还有反向弧
int head[N], edgenum;
void add(int u, int v, ll cap, ll rw = 0){ //如果是有向边则:add(u,v,cap); 如果是无向边则:add(u,v,cap,cap);
Edge E = { u, v, cap, head[u]};
edge[ edgenum ] = E;
head[u] = edgenum ++;
Edge E2= { v, u, rw, head[v]};
edge[ edgenum ] = E2;
head[v] = edgenum ++;
}
int sign[N];
bool BFS(int from, int to){
memset(sign, -1, sizeof(sign));
sign[from] = 0;
queue<int>q;
q.push(from);
while( !q.empty() ){
int u = q.front(); q.pop();
for(int i = head[u]; i!=-1; i = edge[i].nex)
{
int v = edge[i].to;
if(sign[v]==-1 && edge[i].cap)
{
sign[v] = sign[u] + 1, q.push(v);
if(sign[to] != -1)return true;
}
}
}
return false;
}
int Stack[N], top, cur[N];
ll Dinic(int from, int to){
ll ans = 0;
while( BFS(from, to) )
{
memcpy(cur, head, sizeof(head));
int u = from; top = 0;
while(1)
{
if(u == to)
{
ll flow = inf, loc;//loc 表示 Stack 中 cap 最小的边
for(int i = 0; i < top; i++)
if(flow > edge[ Stack[i] ].cap)
{
flow = edge[Stack[i]].cap;
loc = i;
}
for(int i = 0; i < top; i++)
{
edge[ Stack[i] ].cap -= flow;
edge[Stack[i]^1].cap += flow;
}
ans += flow;
top = loc;
u = edge[Stack[top]].from;
}
for(int i = cur[u]; i!=-1; cur[u] = i = edge[i].nex)//cur[u] 表示u所在能增广的边的下标
if(edge[i].cap && (sign[u] + 1 == sign[ edge[i].to ]))break;
if(cur[u] != -1)
{
Stack[top++] = cur[u];
u = edge[ cur[u] ].to;
}
else
{
if( top == 0 )break;
sign[u] = -1;
u = edge[ Stack[--top] ].from;
}
}
}
return ans;
}
void init(){memset(head,-1,sizeof head);edgenum = 0;}
int n;
ll b[1010][1010], c[1010], B[1010];
ll solve(){
init();
int from = 0, to = n +1;
ll ans = 0;
for(int i = 1; i <= n; i++) ans += B[i];
for(int i = 1; i <= n; i++) {
add(from, i, B[i]);
add(i, to, c[i]);
}
for(int i = 1; i <= n; i++)
for(int j = 1; j <= n; j++)
if(i != j)
add(i, j, b[i][j]);
return ans - Dinic(from, to);
}
void input(){
rd(n);
memset(B, 0, sizeof B);
for(int i = 1; i <= n; i++)
for(int j = 1; j <= n; j++)
rd(b[i][j]), B[i] += b[i][j];
for(int i = 1; i <= n; i++)
rd(c[i]);
}
int main() {
int T; rd(T);
while(T--) {
input();
pt( solve() ); putchar('\n');
}
return 0;
}