• 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/+

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

  • 相关阅读:
    在django中怎么解决没有MySQLdb库的问题
    py下windows用户安装lxml
    发现一个强大的可视化第三方库pyecharts
    failed to create process怎么解决
    做透视表时,提示“数据源引用无效”
    用户运营招聘分析报告
    如何修改启动jupyter的文件路径
    如何卸载EXCEL中的插件?
    解决python3环境下twisted安装问题
    解决python多版本共存问题
  • 原文地址:https://www.cnblogs.com/luyouqi233/p/9191439.html
Copyright © 2020-2023  润新知