[2019多校联考(Round 6 T3)]脱单计划 (费用流)

题面

你是一家相亲机构的策划总监,在一次相亲活动中,有 n 个小区的若干男士和 n个小区的若干女士报名了这次活动,你需要将这些参与者两两匹配(只能男生和 女生相匹配),每个小区都提供了自己的地址,用二维平面上的坐标(x,y)来表示,若 A 男所在小区的地址为(x1,y1),B 女所在小区的地址为(x2,y2),由“距离产生美”可得,A 男不 B 女匹配的亲密值为他们的曼哈顿距离|x1-x2|+|y1-y2|,现在要求你确定一种匹配方案使得总亲密值最大(每位男士只能匹配一位女士,每位女士也只能匹配一位男士)

分析

此题和[AGC 034D]Manhattan Max Matching几乎一模一样

小区之间两两连容量无穷,费用为两点间曼哈顿距离的边,原点到男士所在小区连容量为该小区男士数量,费用为0的边。女士所在小区到汇点同理。这样显然是会超时的。

考虑简化的情况,如果费用为\(x_1-x_2+y_1-y_2\),那么可以建一个辅助点u,\((x_1,y_1)\)男士对应的点向u连费用为\(x_1+y_1\)的边,u向女士\((x_2,y_2)\)连费用为\(-x_2-y_2\)的边。跑费用流的时候费用叠加,就得到了\(x_1-x_2+y_1-y_2\)。这样连边的边数是\(O(n)\)的

有绝对值符号怎么办。把绝对值按符号拆成4种情况。\(|x_1-x_2|+|y_1-y_2|=max(x_1-x_2+y_1-y_2,x_2-x_1+y_1-y_2,x_1-x_2+y_2-y_1,x_2-x_1+y_2-y_1)\)

建4个辅助点对应4种情况,每个点都像上面那样连边。

由于是最大费用,跑出来的是4种情况最大值,恰好就是曼哈顿距离取了绝对值符号后的结果。

代码

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cstring>
  4. #include<algorithm>
  5. #include<ctime>
  6. #include<cstdlib>
  7. #include<queue>
  8. #define INF 0x3f3f3f3f3f3f3f3f
  9. #define maxn 10000
  10. #define maxm 3000000
  11. using namespace std;
  12. typedef long long ll;
  13. int n,m;
  14. inline void qread(int& x){
  15. x=0;
  16. int sign=1;
  17. char c=getchar();
  18. while(c<'0'||c>'9'){
  19. if(c=='-') sign=-1;
  20. c=getchar();
  21. }
  22. while(c>='0'&&c<='9'){
  23. x=x*10+c-'0';
  24. c=getchar();
  25. }
  26. x=x*sign;
  27. }
  28. inline void qread(ll& x){
  29. x=0;
  30. int sign=1;
  31. char c=getchar();
  32. while(c<'0'||c>'9'){
  33. if(c=='-') sign=-1;
  34. c=getchar();
  35. }
  36. while(c>='0'&&c<='9'){
  37. x=x*10+c-'0';
  38. c=getchar();
  39. }
  40. x=x*sign;
  41. }
  42. struct node{
  43. ll x;
  44. ll y;
  45. int c;
  46. }a[maxn+5],b[maxn+5];
  47. inline ll get_dist(node p,node q){
  48. return abs(p.x-q.x)+abs(p.y-q.y);
  49. }
  50. namespace network_flow{
  51. struct edge{
  52. int from;
  53. int to;
  54. int next;
  55. ll flow;
  56. ll cost;
  57. }E[maxm+5];
  58. int head[maxn+5];
  59. int sz=1;
  60. void add_edge(int u,int v,ll w,ll c){
  61. #ifdef DEBUG
  62. // printf("%d->%d vol=%lld cost=%lld\n",u,v,w,c);
  63. #endif
  64. c=-c;
  65. sz++;
  66. E[sz].from=u;
  67. E[sz].to=v;
  68. E[sz].flow=w;
  69. E[sz].cost=c;
  70. E[sz].next=head[u];
  71. head[u]=sz;
  72. sz++;
  73. E[sz].from=v;
  74. E[sz].to=u;
  75. E[sz].flow=0;
  76. E[sz].cost=-c;
  77. E[sz].next=head[v];
  78. head[v]=sz;
  79. }
  80. bool inq[maxn+5];
  81. int pre[maxn+5];
  82. ll minf[maxn+5];
  83. ll dist[maxn+5];
  84. bool spfa(int s,int t){
  85. for(int i=s;i<=t;i++){
  86. inq[i]=0;
  87. pre[i]=0;
  88. dist[i]=INF;
  89. minf[i]=INF;
  90. }
  91. queue<int>q;
  92. q.push(s);
  93. inq[s]=1;
  94. dist[s]=0;
  95. while(!q.empty()){
  96. int x=q.front();
  97. q.pop();
  98. inq[x]=0;
  99. for(int i=head[x];i;i=E[i].next){
  100. int y=E[i].to;
  101. if(E[i].flow&&dist[y]>dist[x]+E[i].cost){
  102. dist[y]=dist[x]+E[i].cost;
  103. pre[y]=i;
  104. minf[y]=min(minf[x],E[i].flow);
  105. if(!inq[y]){
  106. q.push(y);
  107. inq[y]=1;
  108. }
  109. }
  110. }
  111. }
  112. return dist[t]!=INF;
  113. }
  114. void update(int s,int t){
  115. int x=t;
  116. while(x!=s){
  117. int i=pre[x];
  118. E[i].flow-=minf[t];
  119. E[i^1].flow+=minf[t];
  120. x=E[i].from;
  121. }
  122. }
  123. ll mcmf(int s,int t){
  124. ll flow=0,cost=0;
  125. while(spfa(s,t)){
  126. flow+=minf[t];
  127. cost+=minf[t]*dist[t];
  128. update(s,t);
  129. }
  130. return -cost;
  131. }
  132. void solve(){
  133. int s=0,t=n*2+5;
  134. int p1=n*2+1,p2=n*2+2,p3=n*2+3,p4=n*2+4;
  135. for(int i=1;i<=n;i++){
  136. add_edge(s,i,a[i].c,0);
  137. }
  138. for(int i=1;i<=n;i++){
  139. add_edge(i+n,t,b[i].c,0);
  140. }
  141. //绝对值分符号拆成4个,用4个辅助点连边
  142. //因为是最大费用,4种情况取最大值就是绝对值
  143. //这样就把边数从O(n^2)变成O(n)
  144. for(int i=1;i<=n;i++){
  145. //x1-x2+y1-y2
  146. add_edge(i,p1,INF,a[i].x+a[i].y);
  147. add_edge(p1,i+n,INF,-b[i].x-b[i].y);
  148. //x1-x2+y2-y1
  149. add_edge(i,p2,INF,a[i].x-a[i].y);
  150. add_edge(p2,i+n,INF,-b[i].x+b[i].y);
  151. //x2-x1+y1-y2
  152. add_edge(i,p3,INF,-a[i].x+a[i].y);
  153. add_edge(p3,i+n,INF,b[i].x-b[i].y);
  154. //x2-x1+y2-y1
  155. add_edge(i,p4,INF,-a[i].x-a[i].y);
  156. add_edge(p4,i+n,INF,b[i].x+b[i].y);
  157. }
  158. printf("%lld\n",mcmf(s,t));
  159. }
  160. }
  161. int main(){
  162. // freopen("1.in","r",stdin);
  163. qread(n);
  164. for(int i=1;i<=n;i++){
  165. qread(a[i].x);
  166. qread(a[i].y);
  167. qread(a[i].c);
  168. }
  169. for(int i=1;i<=n;i++){
  170. qread(b[i].x);
  171. qread(b[i].y);
  172. qread(b[i].c);
  173. }
  174. network_flow::solve();
  175. }

[2019多校联考(Round 6 T3)]脱单计划 (费用流)的更多相关文章

  1. [多校联考2019(Round 5 T3)]青青草原的表彰大会(dp+组合数学)

    [多校联考2019(Round 5)]青青草原的表彰大会(dp+组合数学) 题面 青青草原上有n 只羊,他们聚集在包包大人的家里,举办一年一度的表彰大会,在这次的表彰大会中,包包大人让羊们按自己的贡献 ...

  2. [多校联考2019(Round 5 T1)] [ATCoder3912]Xor Tree(状压dp)

    [多校联考2019(Round 5)] [ATCoder3912]Xor Tree(状压dp) 题面 给出一棵n个点的树,每条边有边权v,每次操作选中两个点,将这两个点之间的路径上的边权全部异或某个值 ...

  3. [多校联考2019(Round 5 T2)]蓝精灵的请求(二分图染色+背包)

    [多校联考2019(Round 5)]蓝精灵的请求(二分图染色+背包) 题面 在山的那边海的那边住着 n 个蓝精灵,这 n 个蓝精灵之间有 m 对好友关系,现在蓝精灵们想要玩一个团队竞技游戏,需要分为 ...

  4. 三校联考 Day3

    三校联考 Day3 大水题 题目描述:给出一个圆及圆上的若干个点,问两个点间的最远距离. solution 按极角排序,按顺序枚举,显然距离最远的点是单调的,线性时间可解出答案. 大包子的束缚 题目描 ...

  5. 【赛时总结】NOIP2018-三校联考1024

    ◇NOIP三校联考-1024◇ 发现以前的博客写得似乎都很水……基本上都没什么阅读量QwQ 决定改过自新╰( ̄ω ̄o) 就从这篇博客开始吧~ 现场考得无地自容,看到题解才发现一些东西……(我第三题还没 ...

  6. 【五校联考1day2】JZOJ2020年8月12日提高组T2 我想大声告诉你

    [五校联考1day2]JZOJ2020年8月12日提高组T2 我想大声告诉你 题目 Description 因为小Y 是知名的白富美,所以自然也有很多的追求者,这一天这些追求者打算进行一次游戏来踢出一 ...

  7. 【五校联考1day2】JZOJ2020年8月12日提高组T1 对你的爱深不见底

    [五校联考1day2]JZOJ2020年8月12日提高组T1 对你的爱深不见底 题目 Description 出乎意料的是,幸运E 的小R 居然赢了那个游戏.现在欣喜万分的小R 想要写一张明信片给小Y ...

  8. 2019十二省联考 Round 1 && 济南市市中心游记

    在这样一场毒瘤的省选中 这道题目无疑是命题人无私的馈赠 大量精心构造的部分分,涵盖了题目中所有涉及的算法 你可以利用这道题目,对你是否能够进入省队进行初步检查 经典的模型.较低的难度和不大的代码量,能 ...

  9. [2017/5/28]FJ四校联考

    来自FallDream的博客,未经允许,请勿转载,谢谢. 话说这一段时间算是过去了,好久好久之后终于又有联考了  没想到这次到我们学校出题,昨天才想起来,临时花一天赶了一套,我出了一个sbFFT,质量 ...

随机推荐

  1. 【JZOJ2156】【2017.7.10普及】复仇者vsX战警之训练

    题目 月球上反凤凰装甲在凤凰之力附身霍普之前,将凤凰之力打成五份,分别附身在X战警五大战力上面辐射眼.白皇后.钢力士.秘客和纳摩上(好尴尬,汗). 在凤凰五使徒的至高的力量的威胁下,复仇者被迫逃到昆仑 ...

  2. electron-vue ipcRenderer.on() 调用多次

    methods: { isSave (ev) { this.localFileUrl = ev.localFileUrl // 本地的路径 ipcRenderer.send('save-dialog' ...

  3. 【leetcode】Valid Triangle Number

    题目: Given an array consists of non-negative integers, your task is to count the number of triplets c ...

  4. 实战build-react(三)+ style-components

    npm install --save style-components https://www.jianshu.com/p/27788be90605(copy) "axios": ...

  5. bootstrap editable初始化后表单

    function loadData() { var url = "${ctx }/sys/marketing/product/page"; $('#tablepager').boo ...

  6. android intent调用系统camera

    利用android的camera通常有两种方式:利用intent调用系统的camera,或者结合surfaceview实现自己定制的camera.先分别对这两种方法说明如下: 一.使用系统自配的cam ...

  7. swagger2简单使用

    1.引入jar <!--引入swagger--> <dependency> <groupId>io.springfox</groupId> <ar ...

  8. Maven聚合和继承

    一.建立以pom为packaging的项目为,然后再以这一个项目为parent project来聚合其他子项目         新建立一个以pom的项目 改写pom文件,依赖web-common,这样 ...

  9. __file__, sys._getframe().f_lineno 当前文件的行号

    当前文件的行号 try: f = open(sys.argv[1], "rb") address_book.ParseFromString(f.read()) f.close()e ...

  10. Java 语言特性之 Annotation 注解

    利用 Java 的反射机制,可以在运行时获取 Java 类的注解信息. 注解 注解的特性 注解是 Java 5 的一个新特性,是插入代码中的一种注释或者说是元数据.注解并不是程序代码,可以对程序作出解 ...