• CodeVS 1022-覆盖


    原题

    题目描述 Description

    有一个N×M的单位方格中,其中有些方格是水塘,其他方格是陆地.如果要用1×2的矩阵区覆盖(覆盖过程不容许有任何部分重叠)这个陆地,那么最多可以覆盖多少陆地面积.

    输入描述 Input Description

    输入文件的第一行是两个整数N,M  (1<=N,M<=100),第二行为一个整数K( K<=50),接下来的K行,每行两个整数X,Y表示K个水塘的行列位置。(1<=X<=N,1<=Y<=M)。

     

    输出描述 Output Description

    输出所覆盖的最大面积块(1×2面积算一块)。

    样例输入 Sample Input

    4 4

    6

    1 1

    1 4

    2 2

    4 1

    4 2

    4 4

    样例输出 Sample Output

    4

    题解

    这道题一开始看以为是什么状压DP就一直没敢做,但最近周围各位神犇都在写这道题,就认真地再看了一次.

    由于是求1*2或者2*1的块的个数,那就可以用二分图来做.

    建图的时候就把相邻两个点连接起来.

    每个点最多只能在二分图的左边出现一次,如果某个点在二分图的右边出现过一次,那么它同样不能加入二分图的左边.

    由于我的算法是Dinic,因此要建一个原点与二分图左边的每个点一一相连.

    同样的,二分图右边的每个点也要与汇点建一条边,但值得注意的是,二分图右边的点最多只能和汇点连一条边.

    因此,我们就要建立两个数组usex/usey分别表示某一个点是否在二分图的左边或是右边出现,是为True,否为False.

    建图之后直接套Dinic就OK了.

    Code:

    const fx:array[1..4] of longint=(1,-1,0,0);
    const fy:array[1..4] of longint=(0,0,1,-1);
    var ne,b,c,q:array[0..100000] of longint;
    var fir,dis:array[0..1001] of longint;
    var usex,usey:array[0..1001] of boolean;
    var a:array[0..100,0..100] of boolean;
    var i,j,n,m,tot,x,y,k,ans:longint;
    function v(x,y:longint):longint; begin exit((x-1)*m+y); end;
    procedure add(x,y:longint);
    var ty,tx,i,xx,yy:longint;
    begin
      tx:=v(x,y);
      usex[tx]:=true;
      for i:=1 to 4 do
      begin
        xx:=x+fx[i];yy:=y+fy[i];
        ty:=v(xx,yy);
        if (not a[xx,yy])and(not usex[ty])and(xx<=n)and(xx>0)and(yy<=m)and(yy>0) then
        begin
          inc(tot);b[tot]:=tx;c[tot]:=1;ne[tot]:=fir[0];fir[0]:=tot;//左边的点与原点建边
          inc(tot);b[tot]:=0;c[tot]:=0;ne[tot]:=fir[tx];fir[tx]:=tot;
          inc(tot);b[tot]:=ty;c[tot]:=1;ne[tot]:=fir[tx];fir[tx]:=tot;//两点之间建边
          inc(tot);b[tot]:=tx;c[tot]:=0;ne[tot]:=fir[ty];fir[ty]:=tot;
          if not usey[ty] then//只能和汇点建一条边!!!只能和汇点建一条边!!!只能和汇点建一条边!!!
          begin
            inc(tot);b[tot]:=m*n+1;c[tot]:=1;ne[tot]:=fir[ty];fir[ty]:=tot;
            inc(tot);b[tot]:=ty;c[tot]:=0;ne[tot]:=fir[n*m+1];fir[n*m+1]:=tot;
          end;
          usey[ty]:=true;
        end;
      end;
    end;
    procedure bfs;
    var i,h,t,now:longint;
    begin
      for i:=0 to n*m+1 do dis[i]:=-1;
      h:=1;t:=1;dis[0]:=0;q[1]:=0;
      while h<=t do
      begin
        now:=q[h];j:=fir[now];
        while j>0 do
        begin
          if (c[j]>0)and(dis[b[j]]=-1) then
          begin
            dis[b[j]]:=dis[now]+1;
            inc(t);q[t]:=b[j];
          end;j:=ne[j];
        end;inc(h);
      end;
    end;
    function dfs(x,mx:longint):longint;
    var k,j:longint;
    begin
      if x=n*m+1 then exit(mx);j:=fir[x];
      while j>0 do
      begin
        if (c[j]>0)and(dis[b[j]]=dis[x]+1) then
        begin
          if mx<c[j] then k:=dfs(b[j],mx) else k:=dfs(b[j],c[j]);
          dec(c[j],k);
          if odd(j) then inc(c[j+1],k) else inc(c[j-1],k);
          if k>0 then exit(k);
        end;j:=ne[j];
      end;
      exit(0);
    end;
    begin
      readln(n,m);
      readln(k);
      for i:=1 to k do begin readln(x,y);a[x,y]:=true; end;
      fillchar(fir,sizeof(fir),255);
      for i:=1 to n do for j:=1 to m do if (not a[i,j])and(not usey[v(i,j)]) then add(i,j);
      while true do
      begin
        bfs;//建分层图
        if dis[n*m+1]=-1 then break;//如果到不了汇点则跳出循环
        ans:=ans+dfs(0,maxlongint);
      end;
      writeln(ans);
    end.

    最后我发现我似乎是这道题唯一0ms过的人233333......
    测试点#cover0.in 结果: 内存使用量: 256kB 时间使用量: 0ms 
    测试点#cover1.in 结果: 内存使用量: 256kB 时间使用量: 0ms 
    测试点#cover2.in 结果: 内存使用量: 256kB 时间使用量: 0ms 
    测试点#cover3.in 结果: 内存使用量: 256kB 时间使用量: 0ms 
    测试点#cover4.in 结果: 内存使用量: 256kB 时间使用量: 0ms 
    测试点#cover5.in 结果: 内存使用量: 256kB 时间使用量: 0ms 
    测试点#cover6.in 结果: 内存使用量: 256kB 时间使用量: 0ms 
    测试点#cover7.in 结果: 内存使用量: 256kB 时间使用量: 0ms 
    测试点#cover8.in 结果: 内存使用量: 256kB 时间使用量: 0ms 
    测试点#cover9.in 结果: 内存使用量: 256kB 时间使用量: 0ms 
  • 相关阅读:
    Linux 虚拟机虚拟网卡问题导致无法连接问题
    使用 Load Balancer,Corosync,Pacemaker 搭建 Linux 高可用集群
    如何在 Linux 虚拟机上扩展根文件系统
    Linux 虚拟机中配置 GNOME + VNC
    在 Linux 中使用 Azure Premium 存储的基本优化指南
    如何为运行的 ARM Linux 启用 LAD2.3 版本的诊断扩展
    如何解决 Linux 虚拟机磁盘设备名不一致的问题
    Java 调用 Rest api 设置经典 Linux 虚拟机的实例启停
    CentOS: 将虚拟机迁移到 Azure (以阿里云为例)
    Linux 虚拟机的计划维护
  • 原文地址:https://www.cnblogs.com/HAdolf-HQY/p/6575030.html
Copyright © 2020-2023  润新知