==線代好難
#include#include #include #include #include #include #include template 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 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 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; }