这一类的问题都可以这样分治来做。
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define maxn 150 #define inf 2000000000 using namespace std; int t,n,a[maxn][maxn],b[maxn][maxn]; int lx[maxn],ly[maxn],slack[maxn],linky[maxn],w[maxn][maxn]; bool visx[maxn],visy[maxn]; struct point { int a,b; point (int a,int b):a(a),b(b) {} point () {} friend bool operator < (const point & x,const point & y) { return (long long)x.a*x.b<(long long)y.a*y.b; } friend point operator - (const point & x,const point & y) { return point(x.a-y.a,x.b-y.b); } friend int operator * (const point & x,const point & y) { return x.a*y.b-x.b*y.a; } }ans; bool hungary(int x) { visx[x]=true; for (int i=1;i<=n;i++) { if (visy[i]) continue; int t=-lx[x]-ly[i]+w[x][i]; if (!t) { visy[i]=true; if (linky[i]==-1 || (hungary(linky[i]))) { linky[i]=x; return true; } } else slack[i]=min(slack[i],t); } return false; } point KM() { for (int i=1;i<=n;i++) linky[i]=-1,lx[i]=inf,ly[i]=0; for (int i=1;i<=n;i++) for (int j=1;j<=n;j++) lx[i]=min(lx[i],w[i][j]); for (int i=1;i<=n;i++) { for (int j=1;j<=n;j++) slack[j]=inf; for (;;) { memset(visx,false,sizeof(visx)); memset(visy,false,sizeof(visy)); if (hungary(i)) break; int d=inf; for (int j=1;j<=n;j++) if (!visy[j]) d=min(d,slack[j]); for (int j=1;j<=n;j++) { if (visx[j]) lx[j]+=d; if (visy[j]) ly[j]-=d; else slack[j]-=d; } } } point ret=point(0,0); for (int i=1;i<=n;i++) { ret.a+=a[linky[i]][i]; ret.b+=b[linky[i]][i]; } if (ret<ans) ans=ret; return ret; } void DAC(point A,point B) { for (int i=1;i<=n;i++) for (int j=1;j<=n;j++) w[i][j]=a[i][j]*(A.b-B.b)+b[i][j]*(B.a-A.a); point C=KM(); if ((C-A)*(B-A)<=0) return; DAC(A,C);DAC(C,B); } void work() { scanf("%d",&n);ans=point(inf,inf); 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++) w[i][j]=a[i][j]; point A=KM(); for (int i=1;i<=n;i++) for (int j=1;j<=n;j++) w[i][j]=b[i][j]; point B=KM(); DAC(A,B); printf("%d\n",ans.a*ans.b); } int main() { scanf("%d",&t); for (int i=1;i<=t;i++) work(); return 0; }
时间: 2024-10-08 10:29:40