基本上是照着蓝书写的
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N=5e4+5,M=5e5+5,delta=25;
const ll INF=(1ll<<55);
ll P[100][100],Q[100][100];
int n,m,s,t;
int head[N],ver[M],Next[M],tot;
int pre[M];
ll d[N],incf[N],edge[M],cost[M];
ll maxflow,maxcost;
bool v[N];
void add(int x,int y,ll z,ll c){
ver[tot]=y; edge[tot]=z; Next[tot]=head[x]; cost[tot]=c; head[x]=tot++;
ver[tot]=x; edge[tot]=0; Next[tot]=head[y]; cost[tot]=-c; head[y]=tot++;
}
bool EK_spfa(){
memset(d,0xcf,sizeof(d));
memset(v,0,sizeof(v));
queue<int>q;
q.push(s); v[s]=1; d[s]=0;
incf[s]=INF;
while(q.size()){
int x=q.front();
v[x]=0; q.pop();
for(int i=head[x];~i;i=Next[i]){
if(!edge[i]) continue;
int y=ver[i];
ll c=cost[i],z=edge[i];
if(d[y]<d[x]+c){
d[y]=d[x]+c;
incf[y]=min(incf[x],z);
pre[y]=i;
if(!v[y]){v[y]=1; q.push(y);}
}
}
}
if(d[t]==0xcfcfcfcf) return false;
return true;
}
void update(){
int x=t;
while(x!=s){
int i=pre[x];
edge[i]-=incf[t];
edge[i^1]+=incf[t];
x=ver[i^1];
}
maxflow+=incf[t];
maxcost+=d[t]*incf[t];
}
int main(){
//freopen(Name ".in", "r", stdin);
//freopen(Name ".out", "w", stdout);
s=0,t=2*n+1;
memset(head,-1,sizeof(head));
scanf("%d",&n);
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
scanf("%lld",&P[i][j]);
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
scanf("%lld",&Q[i][j]);
}
}
for(int i=1;i<=n;i++){
add(s,i,1,0);
add(i+n,t,1,0);
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
add(i,j+n,1,P[i][j]*Q[j][i]);
}
}
while(EK_spfa()) update();
printf("%lld\n",maxcost);
return 0;
}