zoukankan      html  css  js  c++  java
  • BZOJ3571 & 洛谷3236:[HNOI2014]画框——题解

    https://www.lydsy.com/JudgeOnline/problem.php?id=3571

    https://www.luogu.org/problemnew/show/P3236

    小T准备在家里摆放几幅画,为此他买来了N幅画和N个画框。为了体现他的品味,小T希望能合理地搭配画与画框,使得其显得既不过于平庸也不太违和。对于第 幅画与第 个画框的配对,小T都给出了这个配对的平凡度Aij 与违和度Bij 。整个搭配方案的总体不和谐度为每对画与画框平凡度之和与每对画与画框违和度的乘积。具体来说,设搭配方案中第i幅画与第Pi个画框配对,则总体不和谐度为

    小T希望知道通过搭配能得到的最小的总体不和谐度是多少。

    我能说我debug 1h才发现j打成i了吗TAT

    对于最小代价二分图匹配可以KM算法做(当然费用流是可以的但是O(玄学)对吧……)。

    这个所求表达式形式像极了最小乘积生成树:BZOJ2395:[Balkan 2011]Timeismoney

    所以其实我们只是把生成树部分变成KM就行啦!

    #include<cstdio>
    #include<cctype>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    const int N=102;
    const int INF=0x3f3f3f3f;
    inline int read(){
        int X=0,w=0;char ch=0;
        while(!isdigit(ch)){w|=ch=='-';ch=getchar();}
        while(isdigit(ch))X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
        return w?-X:X;
    }
    struct point{
        int x,y;
        point(int xx=0,int yy=0){x=xx,y=yy;}
        point operator -(const point &b)const{
            return point(x-b.x,y-b.y);
        }
        int operator *(const point &b)const{
            return x*b.y-y*b.x;
        }
    };
    int n,ans,a[N][N],b[N][N];
    int dis[N][N],wx[N],wy[N],match[N],sla[N];
    bool vx[N],vy[N];
    bool dfs(int u){
        vx[u]=1;
        for(int v=1;v<=n;v++){
            if(!vy[v]){
                int w=wx[u]+wy[v]-dis[u][v];
                if(!w){
                    vy[v]=1;
                    if(!match[v]||dfs(match[v])){
                        match[v]=u;return 1;
                    }
                }else sla[v]=min(sla[v],w);
            }
        }
        return 0;
    }
    point KM(){
        point res=point(0,0);
        memset(wx,0,sizeof(wx));
        memset(wy,0,sizeof(wy));
        memset(match,0,sizeof(match));
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                wx[i]=max(wx[i],dis[i][j]);
        for(int i=1;i<=n;i++){
            memset(sla,INF,sizeof(sla));
            while(1){
                memset(vx,0,sizeof(vx));
                memset(vy,0,sizeof(vy));
                if(dfs(i))break;
                int minn=INF;
                for(int j=1;j<=n;j++)
                    if(!vy[j])minn=min(minn,sla[j]);
                for(int j=1;j<=n;j++){
                    if(vx[j])wx[j]-=minn;
                    if(vy[j])wy[j]+=minn;
                    else sla[j]-=minn;
                }
            }
        }
        for(int i=1;i<=n;i++)
            res.x+=a[match[i]][i],res.y+=b[match[i]][i];
        ans=min(ans,res.x*res.y);
        return res;
    }
    void work(point l,point r){
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                dis[i][j]=-(a[i][j]*(l.y-r.y)+b[i][j]*(r.x-l.x));
        point mid=KM();
        if((r-l)*(mid-l)>=0)return;
        work(l,mid);work(mid,r);
    }
    int main(){
        int t=read();
        while(t--){
            ans=INF;n=read();
            for(int i=1;i<=n;i++)
                for(int j=1;j<=n;j++)
                    a[i][j]=read();
            for(int i=1;i<=n;i++)
                for(int j=1;j<=n;j++)
                    b[i][j]=read();
            for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)dis[i][j]=-a[i][j];
            point p1=KM();
            for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)dis[i][j]=-b[i][j];
            point p2=KM();
            work(p1,p2);
            printf("%d
    ",ans);
        }
        return 0;
    }

    +++++++++++++++++++++++++++++++++++++++++++

    +本文作者:luyouqi233。               +

    +欢迎访问我的博客:http://www.cnblogs.com/luyouqi233/+

    +++++++++++++++++++++++++++++++++++++++++++

  • 相关阅读:
    linux 开机启动设置
    Ubuntu安装Oracle时出现乱码,及其他安装错误
    ubuntu 设置DNS
    opencv cuda TK1 TX1 兼容设置
    int to string
    post文件的html
    vc 获得调用者的模块名称
    dlib landmark+人面识别
    android破解
    jquery $(document).ready() 与window.onload的区别
  • 原文地址:https://www.cnblogs.com/luyouqi233/p/9191439.html
Copyright © 2011-2022 走看看