博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
BZOJ3571 & 洛谷3236:[HNOI2014]画框——题解
阅读量:6277 次
发布时间:2019-06-22

本文共 3010 字,大约阅读时间需要 10 分钟。

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

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

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

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

这个所求表达式形式像极了最小乘积生成树:

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

#include
#include
#include
#include
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\n",ans); } return 0;}

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

+本文作者:luyouqi233。               +

+欢迎访问我的博客:+

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

转载于:https://www.cnblogs.com/luyouqi233/p/9191439.html

你可能感兴趣的文章
Linux的dd命令
查看>>
从服务器下载一个离线包,格式为gz的压缩包,怎么解压呢。
查看>>
vim使用点滴
查看>>
embedded linux学习中几个需要明确的概念
查看>>
mysql常用语法
查看>>
Morris ajax
查看>>
【Docker学习笔记(四)】通过Nginx镜像快速搭建静态网站
查看>>
ORA-12514: TNS: 监听程序当前无法识别连接描述符中请求的服务
查看>>
<转>云主机配置OpenStack使用spice的方法
查看>>
java jvm GC 各个区内存参数设置
查看>>
[使用帮助] PHPCMS V9内容模块PC标签调用说明
查看>>
关于FreeBSD的CVSROOT的配置
查看>>
基于RBAC权限管理
查看>>
基于Internet的软件工程策略
查看>>
数学公式的英语读法
查看>>
留德十年
查看>>
迷人的卡耐基说话术
查看>>
PHP导出table为xls出现乱码解决方法
查看>>
PHP问题 —— 丢失SESSION
查看>>
PyCairo指南--目录
查看>>