为了提高智商,ZJY开始学习线性代数。她的小伙伴菠萝给她出了这样一个问题:给定一个n×nn×nn×n的矩阵BBB和一个1×n1×n1×n的矩阵CCC。求出一个1×n1×n1×n的01矩阵AAA。使得D=(A×B−C)×ATD=(A×B-C)×A^{\sf T}D=(A×B−C)×AT最大,其中ATA^{\sf T}AT为AAA的转置。输出DDD。
其实这个题目本身不算难,只要把它给展开,然后就会发现整个式子变成了
(推理过程表示懒得打了QAQ)
然后看着这个式子我们可以这么理解,同时选 ai 和 aj 可以获得 bij 的收益,而选 ai 会有 ci 的损失,那么这就是很明显的网络流问题了
#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define re register
#define gc getchar()
inline int read() {
re int x=0,f=1;
re char ch=gc;
while(ch<'0'||ch>'9') {
if(ch=='-') f=-1;
ch=gc;
}
while(ch>='0'&&ch<='9') x=(x<<1)+(x<<3)+(ch^48),ch=gc;
return x*f;
}
const int N=4001000,INF=(1<<29);
struct node {
int next,to,w;
} e[N<<4];
int h[N],n,cnt=1,s,t,m;
inline void add(int u,int v,int w) {
e[++cnt]=(node) {h[u],v,w},h[u]=cnt;
e[++cnt]=(node) {h[v],u,0},h[v]=cnt;
}
#define QXX(u) for(int i=h[u],v;v=e[i].to,i;i=e[i].next)
int deep[N];
inline int bfs() {
queue<int> q;
q.push(s);
for (int i=1; i<=t; ++i) deep[i] = 0;
deep[s]=1;
while(!q.empty()) {
int u=q.front();
q.pop();
QXX(u) if(e[i].w&&!deep[v]) {
deep[v]=deep[u]+1;
q.push(v);
if(v==t) return 1;
}
}
return 0;
}
int dfs(int u,int flow) {
if(u==t) return flow;
int res=flow;
QXX(u) if(e[i].w&&deep[v]==deep[u]+1) {
int k=dfs(v,min(res,e[i].w));
e[i].w-=k;
e[i^1].w+=k;
res-=k;
}
if(res==flow)
deep[u]=0;
return flow-res;
}
int id(int i,int j) {
return (i-1)*n+1;
}
int ans,maxf=0;
int b[505],c[505][505];
int main() {
// freopen("x.txt","r",stdin);
n = read();
for(int i = 1; i <= n; i++) {
for(int j = 1; j <= n; j++) {
c[i][j] = read();
}
}
for(int i = 1; i <= n; i++) b[i] = read();
s=0, t=n*(n+1)+1;
for(int i=1; i<=n; i++) {
for(int j=1; j<=n; j++) {
add(s,i*n+j, c[i][j]);
add(i*n+j,i,INF);
add(i*n+j,j,INF);
maxf+=c[i][j];
}
}
for(int i=1; i<=n; i++)
add(i, t, b[i]);
while(bfs()) {
while((ans=dfs(s,INF))) maxf-=ans;
}
cout<<maxf<<endl;
return 0;
}