Link:

BZOJ 3571 传送门

Solution:

和 BZOJ2395 的建模完全相同,(BZOJ2395 题解传送门

仅仅是将其中的基础问题由最小生成树改成了二分图最大完美匹配

只要将原来的Kruscal模块改为KM算法即可

Code:

//by NewErA
#include <bits/stdc++.h> using namespace std;
typedef long long ll;
const int INF=<<; struct Vector
{
int x,y;
Vector(const int &A,const int &B){x=A,y=B;}Vector(){}
};
Vector operator - (const Vector &a,const Vector &b){return Vector(a.x-b.x,a.y-b.y);}
int Cross(const Vector &a,const Vector &b){return a.x*b.y-a.y*b.x;} const int MAXN=;
int T,n,G[MAXN][MAXN],dat1[MAXN][MAXN],dat2[MAXN][MAXN];
Vector mina,minb,ans;
ll res; int match[MAXN*],slack[MAXN*],lx[MAXN],ly[MAXN];
bool visx[MAXN],visy[MAXN]; bool dfs(int u)
{
visx[u]=true;
for(int i=;i<=n;i++)
{
if(visy[i]) continue;
int d=lx[u]+ly[i]-G[u][i];
if(!d)
{
visy[i]=true;
if(match[i]==- || dfs(match[i]))
{
match[i]=u;
return true;
}
}
else slack[i]=min(d,slack[i]);
}
return false;
} Vector KM() //$O(n^3)$的KM做法
{
memset(match,-,sizeof(match));
fill(lx,lx+MAXN,-INF);memset(ly,,sizeof(ly));
for(int i=;i<=n;i++)
for(int j=;j<=n;j++)
lx[i]=max(lx[i],G[i][j]);
for(int i=;i<=n;i++)
{
fill(slack,slack+MAXN,INF);
while(true)
{
memset(visx,,sizeof(visx));
memset(visy,,sizeof(visy));
if(dfs(i)) break;
else
{
int d=INF;
for(int i=;i<=n;i++)
if(!visy[i]) d=min(d,slack[i]);
for(int i=;i<=n;i++)
{
if(visx[i]) lx[i]-=d;
if(visy[i]) ly[i]+=d;
else slack[i]-=d;
}
}
}
} Vector cur=Vector(,);
for(int i=;i<=n;i++)
cur.x+=dat1[match[i]][i],cur.y+=dat2[match[i]][i]; if(res>(ll)cur.x*(ll)cur.y) res=(ll)cur.x*(ll)cur.y; //注意开long long
return cur;
} void Solve(Vector A,Vector B)
{
for(int i=;i<=n;i++)
for(int j=;j<=n;j++)
G[i][j]=-(dat1[i][j]*(A.y-B.y)+dat2[i][j]*(B.x-A.x)); //修改权值
Vector C=KM();
if(Cross(B-A,C-A)>=) return;
Solve(A,C);Solve(C,B);
} int main()
{
cin >> T;
while(T--)
{
cin >> n;res=*;
for(int i=;i<=n;i++)
for(int j=;j<=n;j++)
cin >> dat1[i][j],G[i][j]=-dat1[i][j]; //最小匹配转为最大匹配,权值由正变为负即可
for(int i=;i<=n;i++)
for(int j=;j<=n;j++)
cin >> dat2[i][j];
mina=KM();
for(int i=;i<=n;i++)
for(int j=;j<=n;j++)
G[i][j]=-dat2[i][j];
minb=KM();
Solve(mina,minb);
cout << res << endl;
}
return ;
}

Review:

1、需要注意的就是最小匹配转为最大匹配的手法:

将原来的正权值求最小变为负权值求最大

2、千万不能再忘开long long 了!

最新文章

  1. java中的方法重载与重写以及方法修饰符
  2. Final-阶段站立会议3
  3. 【转】SVN库的迁移
  4. eBay 消息发送(2)
  5. Java-HTTP连接时如何使用代理(二)—— Proxy类方式
  6. indexedDB article
  7. 全国计算机等级考试二级教程-C语言程序设计_第9章_数组
  8. windowsxp系统下SVN添加新用户
  9. iOS程序进入后台,延迟指定时间退出
  10. iOS之RunLoop
  11. django-xadmin ModelAdmin中定义object_list_template无效的问题
  12. js对象与字符串的想到转换
  13. django 把函数装饰器变为方法装饰器
  14. 九度OJ1111题-单词替换
  15. js弹出div层内容(按回退键关闭div层及遮罩)
  16. C++中没有finally,那么应该在哪里关闭资源?
  17. JAVA-数据库之加载JDBC驱动程序
  18. SharePoint 2013的100个新功能之内容管理(一)
  19. CYQ.Data 批量添加数据性能测试(每秒千、万)---003
  20. C# 获取config文件 实体转换

热门文章

  1. 实际上ECMAScript中并没有对类的定义
  2. jupyter、flask、tornado、djiango安装
  3. bzoj 1060 贪心
  4. bzoj 3212 线段树
  5. 阻塞DOM
  6. 【Git】GitHub之多人开发一个项目
  7. DWM.EXE进程(Desktop Window Manager)不能删除
  8. Swift学习三
  9. POJ3180(有向图强连通分量结点数&gt;=2的个数)
  10. 四维偏序(K-D-Tree+rebuild)