zoukankan      html  css  js  c++  java
  • 【codevs1907】方格取数3(最大流最小割定理)

      网址:http://codevs.cn/problem/1907/

      题意:在一个矩阵里选不相邻的若干个数,使这些数的和最大。

      我们可以把它看成一个最小割,答案就是矩阵中的所有数-最小割。先把矩阵按国际象棋棋盘黑白染色(即把相邻的点分别染成白色和黑色),然后黑点连源点,白点连汇点。割掉一个点到源/汇的边就是不选择这个点,最后的目的就是使源到汇不连通(不引发题目不能选择位置相邻的数的矛盾)。

      然而最小割怎么求呢?

      于是我们就要引入一个定理:最大流最小割定理。它的意思就是说,在一个图中,a点到b点的最小割=a到b的最大流。

      然而我并不会证……这里口胡一个想法:最大流就是沿着剩余网络不断地流,每流一次相当于删掉剩余网络的一条边,流到不能流为止。而最小割也是不断地割直到不连通。于是最小割=最大流。

      答案就这样变成了求最大流。

      具体怎么建图,就是把黑/白点到源/汇的边的流量定为这个位置的上数,而黑白点之间的边,因为不能把它割掉,所以把它的流量设为一个极大数。

      于是就过了。

      代码:

    var a:array[0..1010,0..1010]of longint;
      s:array[0..50,0..50]of longint;
      l,q:array[0..1010]of longint;
      n,m,nn,i,j,k,h,t:longint;
      ans,sum:int64;
    function num(x,y:longint):longint;
    begin
      exit((x-1)*m+y);
    end;
    function dfs(now,ll:longint):longint;
    var p,i:longint;
    begin
      if now=nn then exit(ll);
      for i:=1 to nn do
        if(a[now,i]>0)and(l[i]=l[now]+1)then begin
          if a[now,i]<ll then p:=dfs(i,a[now,i])
          else p:=dfs(i,ll);
          a[now,i]:=a[now,i]-p; a[i,now]:=a[i,now]+p;
          if p>0 then exit(p);
        end;
      exit(0);
    end;
    begin
      read(n,m); sum:=0;
      for i:=1 to n do
        for j:=1 to m do begin
          read(s[i,j]);
          sum:=sum+s[i,j];
        end;
      fillchar(a,sizeof(a),0);
      for i:=1 to n do
        for j:=1 to m do
          if (i+j)and 1=0 then a[num(i,j),n*m+1]:=s[i,j]
          else begin
            if i>1 then a[num(i,j),num(i-1,j)]:=1<<25;
            if i<n then a[num(i,j),num(i+1,j)]:=1<<25;
            if j>1 then a[num(i,j),num(i,j-1)]:=1<<25;
            if j<m then a[num(i,j),num(i,j+1)]:=1<<25;
            a[0,num(i,j)]:=s[i,j];
          end;
      nn:=n*m+1; ans:=0;
      while true do begin
        fillchar(l,sizeof(l),0);
        h:=1; t:=1; q[1]:=0; l[0]:=1;
        repeat
          for i:=1 to nn do
            if(a[q[h],i]>0)and(l[i]=0)then begin
              inc(t); q[t]:=i; l[i]:=l[q[h]]+1;
            end;
          inc(h);
        until h>t;
        if l[nn]=0 then break;
        repeat
          k:=dfs(0,1<<25);
          ans:=ans+k;
        until k=0;
      end;
      writeln(sum-ans);
    end.
    codevs1907方格取数
  • 相关阅读:
    php数组·的方法1-数组的操作
    第十一章:DOM扩展
    第十章:DOM
    hxq的库
    第八章:BOM
    第七章:函数表达式2
    第七章:函数表达式
    第五章:引用类型(一)-Object和Array
    舌尖上的程序猿
    计算矩阵运算的乘法次数
  • 原文地址:https://www.cnblogs.com/quzhizhou/p/6714768.html
Copyright © 2011-2022 走看看