[BZOJ3571][HNOI2014]画框

来源:互联网 发布:久其软件 决算 编辑:程序博客网 时间:2024/06/11 05:58

我反正是绝对做不出来。
我们把每个决策的xy看做点(x,y),那么最优解只有可能是下凸壳的点,而且在x最小的点A和y最小的点B之间的下凸壳。我们先求出A、B,观察得在线段AB下方离线段AB最远的点C一定在下凸壳上,这样就可以分治(A,C)和(B,C)了。
怎么求C?
SABCcross(CA,BA)最大。
cross(CA,BA)=cross(((C.xA.x),(C.yA.y)),((B.xA.x),(B.ya.y))=(C.xA.x)(B.ya.y)(C.yA.y)(B.xA.x)=C.x(B.ya.y)C.y(B.xA.x)A.x(B.ya.y)+A.y(B.xA.x)
后两项为定值,只需前两项最大即可。
那么令二分图的权值g(i,j)=(B.ya.y)A[i][j](B.xA.x)B[i][j]跑KM即可。
这一题的复杂度好像并不明确。。。
这里再说一下KM算法的优化,sla要在外层循环清INF,每次DFS不是相等子图中的边则需要更新,然后update记得减去。因为sla是Y’中的点与X中的点的min(l(x)+l(y)g(x,y))

#include<ctime>#include<cstdio>#include<cstdlib>#include<cstring>#include<algorithm>#include<iostream>#include<string>#include<cassert>#include<cmath>#include<vector>#include<queue>#include<stack>#include<map>#include<sstream>#include<climits>#define X first#define Y second#define DB double#define lc now<<1#define rc now<<1|1#define MP make_pair#define LL long long#define pb push_back#define sqr(_) ((_)*(_))#define INF 0x3f3f3f3f#define pii pair<int,int>#define pdd pair<DB,DB>#define ull unsigned LL#define DEBUG(...) fprintf(stderr,__VA_ARGS__)using namespace std;template<typename T>void Read(T& x){    x=0;int flag=0,sgn=1;char c;    while(c=getchar())    {        if(c=='-')sgn=-1;        else if(c>='0'&&c<='9')x*=10,x+=c-'0',flag=1;        else if(flag)break;    }    x*=sgn;}const int MAXN=80;int T,n,A[MAXN][MAXN],B[MAXN][MAXN],G[MAXN][MAXN];struct KM{    bool S[MAXN],T[MAXN];    int lx[MAXN],ly[MAXN],sla[MAXN],left[MAXN];    bool match(int i)    {        S[i]=1;        for(int j=1;j<=n;j++)            if(!T[j])            {                if(lx[i]+ly[j]==G[i][j])                {                    T[j]=1;                    if(!left[j]||match(left[j])){                        left[j]=i;                        return 1;                    }                }                else                    sla[j]=min(sla[j],lx[i]+ly[j]-G[i][j]);            }        return 0;    }    void update()    {        int d=INF;        for(int i=1;i<=n;i++)if(!T[i])            d=min(d,sla[i]);        for(int i=1;i<=n;i++)        {            if(S[i])lx[i]-=d;            if(T[i])ly[i]+=d;            else                sla[i]-=d;        }    }    pii km()    {        pii res=MP(0,0);        memset(left,0,sizeof(left));        memset(ly,0,sizeof(ly));        memset(lx,0,sizeof(lx));        for(int i=1;i<=n;i++)            for(int j=1;j<=n;j++)                lx[i]=max(lx[i],G[i][j]);        for(int i=1;i<=n;i++)        {            memset(sla,INF,sizeof(sla));            while(1)            {                memset(S,0,sizeof(S));                memset(T,0,sizeof(T));                if(match(i))break;                else update();            }        }        for(int i=1;i<=n;i++)        {            res.X+=A[left[i]][i];            res.Y+=B[left[i]][i];        }        return res;    }}Graph;void init(){    Read(n);    for(int i=1;i<=n;i++)        for(int j=1;j<=n;j++)            Read(A[i][j]);    for(int i=1;i<=n;i++)        for(int j=1;j<=n;j++)            Read(B[i][j]);}void build(pii& l,pii& r){    for(int i=1;i<=n;i++)        for(int j=1;j<=n;j++)            G[i][j]=(r.Y-l.Y)*A[i][j]+(l.X-r.X)*B[i][j];}int work(pii l,pii r){    build(l,r);    pii mid=Graph.km();    if(l==mid||r==mid)return min(l.X*l.Y,r.X*r.Y);    return min(work(l,mid),work(mid,r));}void solve(){    for(int i=1;i<=n;i++)        for(int j=1;j<=n;j++)            G[i][j]=-A[i][j];    pii st=Graph.km();    for(int i=1;i<=n;i++)        for(int j=1;j<=n;j++)            G[i][j]=-B[i][j];    pii ed=Graph.km();    cout<<work(st,ed)<<endl;}int main(){#ifndef ONLINE_JUDGE    freopen("frame.in","r",stdin);    freopen("frame.out","w",stdout);#endif    Read(T);    while(T--)    {        init();        solve();    }}
0 0
原创粉丝点击