题解:
似乎是什么乘积最小生成树
然后再加上km
代码:
#include<bits/stdc++.h> const int N=75; using namespace std; struct poi{int x,y;}le,ri; int cas,n,A[N][N],B[N][N],g[N][N],lx[N],ly[N],mat[N],sla[N],vx[N],vy[N]; int operator ==(poi a,poi b){return a.x==b.x&&a.y==b.y;} int dfs(int x) { vx[x]=1; for (int y=1;y<=n;y++) if (!vy[y]) { int t=lx[x]+ly[y]-g[x][y]; if (!t) { vy[y]=1; if (!mat[y]||dfs(mat[y])){mat[y]=x;return 1;} } else sla[y]=min(sla[y],t); } return 0; } poi KM() { memset(lx,0,sizeof(lx)); memset(ly,0,sizeof(ly)); memset(mat,0,sizeof(mat)); for (int i=1;i<=n;i++) for (int j=1;j<=n;j++) lx[i]=max(lx[i],g[i][j]); for (int x=1;x<=n;x++) { memset(sla,63,sizeof(sla)); while (1) { memset(vx,0,sizeof(vx)); memset(vy,0,sizeof(vy)); if (dfs(x)) break; int d=1e9; for (int i=1;i<=n;i++) if (!vy[i]) d=min(d,sla[i]); for (int i=1;i<=n;i++) { if (vx[i]) lx[i]-=d; if (vy[i]) ly[i]+=d; } } } poi ans=(poi){0,0}; for (int i=1;i<=n;i++) ans.x+=A[mat[i]][i],ans.y+=B[mat[i]][i]; return ans; } int solve(poi l,poi r) { for (int i=1;i<=n;i++) for (int j=1;j<=n;j++) g[i][j]=A[i][j]*(r.y-l.y)+B[i][j]*(l.x-r.x); poi mid=KM(); if (l==mid||r==mid) return min(l.x*l.y,r.x*r.y); return min(solve(l,mid),solve(mid,r)); } int main() { scanf("%d",&cas); while (cas--) { scanf("%d",&n); for (int i=1;i<=n;i++) for (int j=1;j<=n;j++) scanf("%d",&A[i][j]); for (int i=1;i<=n;i++) for (int j=1;j<=n;j++) scanf("%d",&B[i][j]); for (int i=1;i<=n;i++) for (int j=1;j<=n;j++) g[i][j]=-A[i][j];le=KM(); for (int i=1;i<=n;i++) for (int j=1;j<=n;j++) g[i][j]=-B[i][j];ri=KM(); printf("%d\n",solve(le,ri)); } return 0; }