题目链接 线性代数 LibreOJ - 2100
首先,A矩阵*B矩阵 - C矩阵,我们会得到一个1*N的行列式,每一项是:
然后再乘以A的转置行列式,
最后我们可以得到的是,我们所求的就是
于是,又知道非0即1,所以就是取或者不取的问题了,又有i、j同时取这个问题,我们必须要解决,于是这里可以利用的性质来解决了。
我们想要这个式子的答案最大,于是,可以利用最小割(最大流)来求解。
对于我们可以给它开成N*N个点。对于我们也是开成N个点,然后就是一个最大流,去知晓哪些点是被我们利用过了的。然后根据上面的公式求解答案。
#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#include <bitset>
#include <unordered_map>
#include <unordered_set>
#define lowbit(x) ( x&(-x) )
#define pi 3.141592653589793
#define e 2.718281828459045
#define INF 0x3f3f3f3f3f3f3f3f
#define HalF (l + r)>>1
#define lsn rt<<1
#define rsn rt<<1|1
#define Lson lsn, l, mid
#define Rson rsn, mid+1, r
#define QL Lson, ql, qr
#define QR Rson, ql, qr
#define myself rt, l, r
using namespace std;
typedef unsigned long long ull;
typedef unsigned int uit;
typedef long long ll;
const int maxN = 2.6e5 + 7, maxM = 1.1e6 + 7;
int N, head[maxN], cnt;
ll b[505][505], c[maxN], sum;
struct Eddge
{
int nex, to; ll flow;
Eddge(int a=-1, int b=0, ll c=0):nex(a), to(b), flow(c) {}
}edge[maxM];
inline void addEddge(int u, int v, ll w)
{
edge[cnt] = Eddge(head[u], v, w);
head[u] = cnt++;
}
inline void _add(int u, int v, ll w) { addEddge(u, v, w); addEddge(v, u, 0); }
struct Max_Flow
{
int gap[maxN], cur[maxN], d[maxN], que[maxN], ql, qr, S, T, node;
inline void init()
{
for(int i=0; i<=node + 1; i++)
{
gap[i] = d[i] = 0;
cur[i] = head[i];
}
++gap[d[T] = 1];
que[ql = qr = 1] = T;
while(ql <= qr)
{
int x = que[ql ++];
for(int i=head[x], v; ~i; i=edge[i].nex)
{
v = edge[i].to;
if(!d[v]) { ++gap[d[v] = d[x] + 1]; que[++qr] = v; }
}
}
}
inline ll aug(int x, ll FLOW)
{
if(x == T) return FLOW;
int flow = 0;
for(int &i=cur[x], v; ~i; i=edge[i].nex)
{
v = edge[i].to;
if(d[x] == d[v] + 1)
{
ll tmp = aug(v, min(FLOW, edge[i].flow));
flow += tmp; FLOW -= tmp; edge[i].flow -= tmp; edge[i ^ 1].flow += tmp;
if(!FLOW) return flow;
}
}
if(!(--gap[d[x]])) d[S] = node + 1;
++gap[++d[x]]; cur[x] = head[x];
return flow;
}
inline ll max_flow()
{
init();
ll ret = aug(S, INF);
while(d[S] <= node) ret += aug(S, INF);
return ret;
}
} mf;
vector<int> vt;
ll tmp_Flow;
inline void init()
{
cnt = 0; mf.node = N + N * N + 2; mf.S = 0; mf.T = N + N * N + 1; sum = 0;
for(int i=0; i<=mf.node; i++) head[i] = -1;
}
inline int get_id(int i, int j) { return N * i + j; }
int main()
{
scanf("%d", &N); init();
for(int i=1; i<=N; i++) for(int j=1; j<=N; j++) scanf("%lld", &b[i][j]);
for(int i=1; i<=N; i++) scanf("%lld", &c[i]);
for(int i=1; i<=N; i++) _add(mf.S, i, c[i]);
for(int i=1; i<=N; i++) for(int j=1; j<=N; j++) _add(j, get_id(i, j), INF);
for(int i=1; i<=N; i++) for(int j=1; j<=N; j++) _add(get_id(i, j), mf.T, b[i][j]);
tmp_Flow = mf.max_flow();
for(int i=0; i<N; i++) if(!edge[i << 1].flow) vt.push_back(i + 1);
int len = (int)vt.size();
for(int j=0, u, v; j<len; j++)
{
u = vt[j];
sum -= c[u];
for(int i=0; i<len; i++)
{
v = vt[i];
sum += b[u][v];
}
}
printf("%lld\n", sum);
return 0;
}