BZOJ 3571 画框

Posted on 2017-01-28 19:20  ziliuziliu  阅读(132)  评论(0编辑  收藏  举报

这一类的问题都可以这样分治来做。

#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;    
}