思考一下我们接触的最小割问题

  1. 最小割的基本问题(可能会和图论的知识相结合,比如bzoj1266,bzoj1797)

  2. 最大权闭合图(bzoj1497)

  3. 最大点权覆盖集,最大点权独立集(bzoj1324)

最近接触到了一类关于最小割新的问题,我也不知道叫什么好

反正它有这么几个特点

  1. 每个点都有两种选择的可能性,设为属于S和属于T,属于S有收益a[i],属于T有收益b[i]

  2. 两点之间可能因为同在一个或不在同一个集合内产生额外的收益

  3. 使收益最大化(废话)

大概就是这个意思,如果看不懂也没关系,我们先从最简单的问题开始分析

首先在满足1的条件下,我们有m对关系,点i和j若同在一个集合,那么就能产生一个额外收益w[i,j];

最终使收益最大化。

对此,我们对于每个点i,我们连s--->i 流量为a[i], i--->t 流量为b[i];

然后对于每对关系(i,j),连i<---j,j--->i 流量都为w[i,j];

然后怎么做呢?根据割的定义,就是s到t没有路

在这里就是,割完之后每个点要么和s连,要么和t连;

我们假如以两个点的图为例,思考一下最小割可能割掉的边(我比较懒,就不发图了)

就会发现,这里的最小割正能使不在一个集合的两个点之间的边被切断

或者使在一个集合的两个点之间的边不被切断

最终ans=∑a[i]+∑b[i]+∑w[i,j]-mincut

这里割对应一种解决问题的方案

好这是最初步,下面就是bzoj2132的问题,

条件2变成了,不在同一个集合里的两点会产生一个额外的收益

我们先按基本问题的方式建图

有了最开始的经验,我们不难猜测,

假如选择一个点集,使其中的点i,颠倒一下使s-->i的流量为b[i],i-->t的流量为a[i];

这样我们再做最小割,不就又变回了最基本的问题吗?

而我们应该怎么选择点集呢?

显然,这个点集内部的点是不能有关系的,并且,这些点是给出关系中一侧的点;

说的明确一点,就是不管S,T,根据关系建得的图G,必须是一个二分图;

那么这道题满不满足呢?

我们对平面图黑白相间染色,显然黑点与白点才会产生关系,

黑点与黑点,白点与白点之间是没有关系——是二分图!

于是这道题就简单了!

 const dx:array[..] of integer=(,,,-);
      dy:array[..] of integer=(,-,,);
      inf=; type node=record
       point,next,flow:longint;
     end; var edge:array[..] of node;
    p,cur,h,numh,pre:array[..] of longint;
    c,num:array[..,..] of longint;
    s,x,y,i,j,k,n,m,len,t:longint; procedure add(x,y,f:longint);
  begin
    inc(len);
    edge[len].flow:=f;
    edge[len].point:=y;
    edge[len].next:=p[x];
    p[x]:=len;
  end; begin
  len:=-;
  fillchar(p,sizeof(p),);
  readln(n,m);
  t:=n*m+;
  for i:= to n do
    for j:= to m do
    begin
      inc(k);
      num[i,j]:=k;
      read(x);
      s:=s+x;
      if (i+j) mod = then   //黑白染色
      begin
        add(,k,x);
        add(k,,x);
      end
      else begin
        add(k,t,x);
        add(t,k,);
      end;
    end;   for i:= to n do
    for j:= to m do
    begin
      read(x);
      s:=s+x;
      if (i+j) mod = then
      begin
        add(num[i,j],t,x);
        add(t,num[i,j],x);
      end
      else begin
        add(,num[i,j],x);
        add(num[i,j],,);
      end;
    end;
  for i:= to n do
    for j:= to m do
      read(c[i,j]);
  for i:= to n do
    for j:= to m do
      for k:= to do
      begin
        x:=i+dx[k];
        y:=j+dy[k];
        if num[x,y]> then
        begin
          s:=s+c[i,j];
          add(num[i,j],num[x,y],c[i,j]+c[x,y]);  //两地建筑物类型不同,增加的额外收益是相互的,一荣俱荣一损俱损
          add(num[x,y],num[i,j],);
        end;
      end;
  writeln(s-sap);  //求最大流省略
end.

2132

下面再扩展这个问题

条件2变为若点i,j同属于S,增加额外收益为w[i,j],

若点i,j同属于T,增加额外收益为r[i,j];  (这就是bzoj2127)

我们对于每个点i,我们连s--->i 流量为a[i], i--->t 流量为b[i];

显然,之前根据关系的建图方法已经不适用了,我们要思考怎么解决同属于S,同属于T所带来的收益

这必须得回到割的意义上来,我们知道割表示损失,我们取不到的

那我们就来分析一下损失:

1. 当i和j同时属于S的时候,我们损失了r[i,j]

2. 当i和j同时属于T的时候,我们损失了w[i,j]

3. 当i,j属于不同的集合,我们损失了w[i,j]+r[i,j]

这有什么用呢?我们可以换一种方式表达

当i属于S时,损失了r[i,j]/2,当j属于S时,损失了r[i,j]/2

当i属于T时,损失了w[i,j]/2,当j属于T时,损失了w[i,j]/2

这样我们再看3,我们还要在增加(w[i,j]+r[i,j])/2的损失

不难发现,问题又变回了最基本的问题

对于点i,我们增加s--->i 流量为r[i,j]/2,t--->i 流量为w[i,j]/2

对于每对关系(i,j),连i<---j,j--->i 流量都为(w[i,j]+r[i,j])/2;

ans=所有可能收益和-mincut

为了方便,我们可以一开始把流量全乘2,最后再除以2即可

友情提示:这道题不加当前弧优化的sap会TLE

 const inf=;
      dx:array[..] of integer=(-,,,);
      dy:array[..] of integer=(,,-,); type node=record
       point,next,flow:longint;
     end; var edge:array[..] of node;
    d,p,cur,h,numh,pre:array[..] of longint;
    a:array[..,..,..] of longint;
    num,b,c:array[..,..] of longint;
    n,m,t,s,x,i,j,k,len,y:longint; function min(a,b:longint):longint;
  begin
    if a>b then exit(b) else exit(a);
  end; procedure add(x,y,f:longint);
  begin
    inc(len);
    edge[len].point:=y;
    edge[len].flow:=f;
    edge[len].next:=p[x];
    p[x]:=len;
  end; function sap:longint;
  var tmp,neck,u,i,j,q:longint;
      flag:boolean;   begin
    numh[]:=t+;
    u:=;
    sap:=;
    cur:=p;
    neck:=inf;
    while h[]<t do
    begin
      d[u]:=neck;
      flag:=false;
      i:=cur[u];
      while i<>- do
      begin
        j:=edge[i].point;
        if (edge[i].flow>) and (h[u]=h[j]+) then
        begin
          flag:=true;
          neck:=min(neck,edge[i].flow);
          cur[u]:=i;
          pre[j]:=u;
          u:=j;
          if u=t then
          begin
            sap:=sap+neck;
            i:=t;
            while i<> do
            begin
              i:=pre[i];
              j:=cur[i];
              dec(edge[j].flow,neck);
              inc(edge[j xor ].flow,neck);
            end;
            neck:=inf;
            u:=;
          end;
          break;
        end;
        i:=edge[i].next;
      end;
      if not flag then
      begin
        dec(numh[h[u]]);
        if numh[h[u]]= then exit;
        tmp:=t;
        i:=p[u];
        q:=;
        while i<>- do
        begin
          j:=edge[i].point;
          if (edge[i].flow>) and (h[j]<tmp) then
          begin
            q:=i;
            tmp:=h[j];
          end;
          i:=edge[i].next;
        end;
        cur[u]:=q;
        h[u]:=tmp+;
        inc(numh[h[u]]);
        if u<> then
        begin
          u:=pre[u];
          neck:=d[u];
        end;
      end;
    end;
  end; begin
  readln(n,m);
  len:=-;
  fillchar(p,sizeof(p),);
  t:=n*m+;
  for i:= to n do
  begin
    for j:= to m do
    begin
      inc(k);
      num[i,j]:=k;
      read(x);
      s:=s+x;
      x:=x shl ;
      b[i,j]:=b[i,j]+x;
    end;
    readln;
  end;
  for i:= to n do
  begin
    for j:= to m do
    begin
      read(x);
      s:=s+x;
      x:=x shl ;
      c[i,j]:=c[i,j]+x;
    end;
    readln;
  end;   for i:= to n- do
  begin
    for j:= to m do
    begin
      read(x);
      s:=s+x;
      b[i,j]:=b[i,j]+x;
      b[i+,j]:=b[i+,j]+x;
      a[i,j,]:=a[i,j,]+x;
      a[i+,j,]:=a[i+,j,]+x;
    end;
    readln;
  end;   for i:= to n- do
  begin
    for j:= to m do
    begin
      read(x);
      s:=s+x;
      c[i,j]:=c[i,j]+x;
      c[i+,j]:=c[i+,j]+x;
      a[i,j,]:=a[i,j,]+x;
      a[i+,j,]:=a[i+,j,]+x;
    end;
    readln;
  end;   for i:= to n do
  begin
    for j:= to m- do
    begin
      read(x);
      s:=s+x;
      b[i,j]:=b[i,j]+x;
      b[i,j+]:=b[i,j+]+x;
      a[i,j,]:=a[i,j,]+x;
      a[i,j+,]:=a[i,j+,]+x;
    end;
    readln;
  end;   for i:= to n do
  begin
    for j:= to m- do
    begin
      read(x);
      s:=s+x;
      c[i,j]:=c[i,j]+x;
      c[i,j+]:=c[i,j+]+x;
      a[i,j,]:=a[i,j,]+x;
      a[i,j+,]:=a[i,j+,]+x;
    end;
    readln;
  end;
  for i:= to n do
    for j:= to m do
    begin
      for k:= to do
      begin
        x:=i+dx[k];
        y:=j+dy[k];
        if num[x,y]> then
        begin
          add(num[i,j],num[x,y],a[i,j,k]); //注意序号的对应
          add(num[x,y],num[i,j],);
        end;
      end;
      add(,num[i,j],b[i,j]);
      add(num[i,j],,);
      add(num[i,j],t,c[i,j]);
      add(t,num[i,j],);
    end;
  writeln(s-sap div );
end.

2127

这个问题最终阶段是bzoj3438 不再是两点间关系而是多点间关系了

即多个点如果同属A集合会产生一个额外收益c1,同属于B集合会产生一个额外收益c2

这就不能用上述的做法了,具体做法见bzoj3438的解题报告

一类最小割bzoj2127,bzoj2132 bzoj3438的更多相关文章

  1. 二分图&网络流&最小割等问题的总结

    二分图基础: 最大匹配:匈牙利算法 最小点覆盖=最大匹配 最小边覆盖=总节点数-最大匹配 最大独立集=点数-最大匹配 网络流: 技巧: 1.拆点为边,即一个点有限制,可将其转化为边 BZOJ1066, ...

  2. 【bzoj3894】文理分科 网络流最小割

    原文地址:http://www.cnblogs.com/GXZlegend 题目描述 文理分科是一件很纠结的事情!(虽然看到这个题目的人肯定都没有纠结过) 小P所在的班级要进行文理分科.他的班级可以用 ...

  3. BZOJ3144 [Hnoi2013]切糕 【最小割】

    题目 输入格式 第一行是三个正整数P,Q,R,表示切糕的长P. 宽Q.高R.第二行有一个非负整数D,表示光滑性要求.接下来是R个P行Q列的矩阵,第z个 矩阵的第x行第y列是v(x,y,z) (1≤x≤ ...

  4. BZOJ 2039 / Luogu P1791 [2009国家集训队]employ人员雇佣 (最小割)

    题面 BZOJ传送门 Luogu传送门 分析 考虑如何最小割建图,因为这仍然是二元关系,我们可以通过解方程来确定怎么建图,具体参考论文 <<浅析一类最小割问题 湖南师大附中 彭天翼> ...

  5. 【BZOJ2132】圈地计划(最小割)

    [BZOJ2132]圈地计划(最小割) 题面 BZOJ 题解 对我而言,不可做!!! 所以我膜烂了ZSY大佬 他的博客写了怎么做... 这,,...太强啦!! 完全想不到黑白染色之后反着连边 然后强行 ...

  6. 【BZOJ2127】happiness(最小割)

    [BZOJ2127]happiness(最小割) 题面 Description 高一一班的座位表是个n*m的矩阵,经过一个学期的相处,每个同学和前后左右相邻的同学互相成为了好朋友.这学期要分文理科了, ...

  7. 【BZOJ3438】小M的作物 最小割

    [BZOJ3438]小M的作物 Description 小M在MC里开辟了两块巨大的耕地A和B(你可以认为容量是无穷),现在,小P有n中作物的种子,每种作物的种子 有1个(就是可以种一棵作物)(用1. ...

  8. 【bzoj2127】happiness 网络流最小割

    题目描述 高一一班的座位表是个n*m的矩阵,经过一个学期的相处,每个同学和前后左右相邻的同学互相成为了好朋友.这学期要分文理科了,每个同学对于选择文科与理科有着自己的喜悦值,而一对好朋友如果能同时选文 ...

  9. 【BZOJ2132】圈地计划 最小割

    [BZOJ2132]圈地计划 Description 最近房地产商GDOI(Group of Dumbbells Or Idiots)从NOI(Nuts Old Idiots)手中得到了一块开发土地. ...

随机推荐

  1. jQuery 源码分析5: jQuery 基本静态方法(一)

    jQuery在初始化过程中会为自己扩展一些基本的静态方法和属性,以下是jQuery 1.11.3版本 239 ~ 564行间所扩展的静态属性和方法   jQuery.extend({ // 为每个jQ ...

  2. 九度OJ 1504 把数组排成最小的数【算法】-- 2009年百度面试题

    题目地址:http://ac.jobdu.com/problem.php?pid=1504 题目描述: 输入一个正整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个.例如 ...

  3. S.O.L.I.D

    S.O.L.I.D.是一组面对面向对象设计的最佳实践的设计原则.术语来自Robert C.Martin的著作Agile Principles, Patterns, and Practices in C ...

  4. 生产项目加入到SVN版本控制

    零.介绍 每天定时备份是通过ftp打包和同步的方式,这些都是比较粗的备份,没法恢复到指定时间的文件,所以需要用到svn控制版本. (请不要问我为什么不用git) 一.现有项目文件加入版本控制 因为项目 ...

  5. MySQL5.7 linux二进制安装

    200 ? "200px" : this.width)!important;} --> 介绍 MySQL5.7出来也有大半年了,业内也一直在宣传5.7有多么的N,官网的也是宣 ...

  6. (转)互联网协议入门 ------ HTTP(1)

    作者:阮一峰 原文:http://www.ruanyifeng.com/blog/2012/06/internet_protocol_suite_part_ii.html 我们每天使用互联网,你是否想 ...

  7. Linux是一门真正的黑客高手艺术

    黑客这个词从诞生到现在,从来就没有解释为“高级入侵者”.“病毒制造者”或者“QQ盗号者”过.我至今不清楚在中国是谁先把黑客和这些无聊的词汇联系在了一起,导致如此多的人被误导.但有一点是肯定的,不负责任 ...

  8. Python复杂多重排序

    1. cmp函数是python自带的函数,用于比较两个参数哪个大哪个小 print cmp(2, 3) # -1 如果第一个参数比第二个小,就返回-1,两个元素相等,返回0,否则返回1 2.所以就可以 ...

  9. WPF读书笔记(第一天)

    今天开始学习WPF,大家都推荐<深入浅出WPF>这本书,一下是我觉得此书中重要的地方,记录下来以便以后回顾,也希望其他人看到了对你们有帮助. 1.XAML是可扩展应用程序标记语言 是WPF ...

  10. hdu 2087 剪花布条 KMP多次匹配

    剪花布条 Problem Description 一块花布条,里面有些图案,另有一块直接可用的小饰条,里面也有一些图案.对于给定的花布条和小饰条,计算一下能从花布条中尽可能剪出几块小饰条来呢?   I ...