博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
BZOJ3571 [Hnoi2014]画框 【分治 + KM算法】
阅读量:5124 次
发布时间:2019-06-13

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

题目链接

题解

如果知道最小乘积生成树,那么这种双权值乘积最小就是裸题了

将两权值和作为坐标,转化为二维坐标系下凸包上的点,然后不断划分分治就好了

这里求的是最小匹配值,每次找点套一个二分图最小权匹配

为什么用KM算法?因为这道题丧心病狂卡费用流QAQ

写完就A啦,十分的感人

#include
#include
#include
#include
#include
#define LL long long int#define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)#define REP(i,n) for (int i = 1; i <= (n); i++)#define BUG(s,n) for (int i = 1; i <= (n); i++) cout<
<<' '; puts("");using namespace std;const int maxn = 75,maxm = 100005,INF = 1000000000;inline int read(){ int out = 0,flag = 1; char c = getchar(); while (c < 48 || c > 57){if (c == '-') flag = -1; c = getchar();} while (c >= 48 && c <= 57){out = (out << 3) + (out << 1) + c - 48; c = getchar();} return out * flag;}int n,X[maxn][maxn],Y[maxn][maxn];int w[maxn][maxn],expa[maxn],expb[maxn],cp[maxn],visa[maxn],visb[maxn],dl[maxn];struct point{int x,y;}ans;inline point operator -(const point& a,const point& b){ return (point){a.x - b.x,a.y - b.y};}inline LL operator *(const point& a,const point& b){ return 1ll * a.x * b.y - 1ll * a.y * b.x;}inline bool operator <(const point& a,const point& b){ return 1ll * a.x * a.y == 1ll * b.x * b.y ? a.x < b.x : 1ll * a.x * a.y < 1ll * b.x * b.y;}bool dfs(int u){ visa[u] = true; REP(i,n) if (!visb[i]){ int kl = expa[u] + expb[i] - w[u][i]; if (!kl){ visb[i] = true; if (!cp[i] || dfs(cp[i])) {cp[i] = u; return true;} } else dl[i] = min(dl[i],kl); } return false;}point km(){ REP(i,n) expa[i] = -INF,expb[i] = cp[i] = 0; REP(i,n) REP(j,n) expa[i] = max(expa[i],w[i][j]); REP(i,n){ REP(j,n) dl[j] = INF; while (true){ REP(j,n) visa[j] = visb[j] = false; if (dfs(i)) break; int kl = INF; REP(j,n) if (!visb[j]) kl = min(kl,dl[j]); REP(j,n){ if (visa[j]) expa[j] -= kl; if (visb[j]) expb[j] += kl; else dl[j] -= kl; } } } point re; re.x = re.y = 0; REP(i,n) re.x += X[cp[i]][i],re.y += Y[cp[i]][i]; if (re < ans) ans = re; return re;}void solve(point A,point B){ REP(i,n) REP(j,n) w[i][j] = -((A.y - B.y) * X[i][j] + (B.x - A.x) * Y[i][j]); point C = km(); if ((C - A) * (B - A) <= 0) return; solve(A,C); solve(C,B);}int main(){ int T = read(); while (T--){ n = read(); ans.x = INF; ans.y = INF; REP(i,n) REP(j,n) X[i][j] = read(); REP(i,n) REP(j,n) Y[i][j] = read(); REP(i,n) REP(j,n) w[i][j] = -X[i][j]; point A = km(); REP(i,n) REP(j,n) w[i][j] = -Y[i][j]; point B = km(); solve(A,B); printf("%d\n",ans.x * ans.y); } return 0;}

转载于:https://www.cnblogs.com/Mychael/p/8995121.html

你可能感兴趣的文章
JCE安装使用报错
查看>>
gulp使用
查看>>
EF+postgresql中的一些问题
查看>>
通过字符串引入模块下的属性
查看>>
Dynamic View and Drop Down Menu
查看>>
十六进制字符串转整形
查看>>
perl语言之列表与数组
查看>>
bzoj1094[ZJOI2007]粒子运动 计算几何
查看>>
SCRUM 12.03
查看>>
js里的面向对象分析-(创建实例化对象)
查看>>
重定向IO
查看>>
LoadRunner函数
查看>>
6.mysql 锁机制
查看>>
洛谷 - P2181 - 对角线 - 打表 - 组合数学
查看>>
node转发请求 .csv格式文件下载 中文乱码问题 + 文件上传笔记
查看>>
Python CODE——Nonblocking I/O client AND Delaying Server
查看>>
[转载]Visual Studio 2010敏捷利剑:详解Scrum
查看>>
JAVA四则运算(读写文件)
查看>>
Q&A-3:
查看>>
struts学习
查看>>