【Codevs1227】方格取数2(费用流)

题意:给出一个n*n的矩阵,每一格有一个非负整数Aij,(Aij <= 1000)

现在从(1,1)出发,可以往右或者往下走,最后到达(n,n),每达到一格,把该格子的数取出来,该格子的数就变成0,

这样一共走K次,现在要求K次所达到的方格的数的和最大。

n<=50,k<=10

思路:费用流

将每个点裂成一个出点和一个入点(i,j,1..2),这个思路与最大流类似

(i,j,1)->(i,j,2) 连两条边:

容量为1,费用为a[i,j]

容量为K,费用为0

(i,j,2)->(i+1,j,1)连容量为K,费用为0的边 (i,j+1)类似

(n,n,2)->T 连流量为K,费用为0的边限制流量

跑最大费用最大流就行了,其实就是SPFA的三角不等式改个方向

  1 var fan:array[1..200000]of longint;
  2     q:array[0..20000]of longint;
  3     head,vet,next,len1,len2:array[1..20000]of longint;
  4     pre:array[1..20000,1..2]of longint;
  5     inq:array[1..20000]of boolean;
  6     dis:array[1..20000]of longint;
  7     a:array[1..50,1..50]of longint;
  8     num:array[1..50,1..50,1..2]of longint;
  9     n,m,k1,i,j,k,tot,s,source,src:longint;
 10     ans:int64;
 11
 12 function min(x,y:longint):longint;
 13 begin
 14  if x<y then exit(x);
 15  exit(y);
 16 end;
 17
 18 procedure add(a,b,c,d:longint);
 19 begin
 20  inc(tot);
 21  next[tot]:=head[a];
 22  vet[tot]:=b;
 23  len1[tot]:=c;
 24  len2[tot]:=d;
 25  head[a]:=tot;
 26
 27  inc(tot);
 28  next[tot]:=head[b];
 29  vet[tot]:=a;
 30  len1[tot]:=0;
 31  len2[tot]:=-d;
 32  head[b]:=tot;
 33 end;
 34
 35 function spfa:boolean;
 36 var u,t,w,i,e,v:longint;
 37 begin
 38  for i:=1 to s do
 39  begin
 40   dis[i]:=-maxlongint;
 41   inq[i]:=false;
 42  end;
 43  t:=0; w:=1; q[1]:=source; inq[source]:=true; dis[source]:=0;
 44  while t<w do
 45  begin
 46   inc(t); u:=q[t mod (s+5)];
 47   inq[u]:=false;
 48   e:=head[u];
 49   while e<>0 do
 50   begin
 51    v:=vet[e];
 52    if (len1[e]>0)and(dis[u]+len2[e]>dis[v]) then
 53    begin
 54     pre[v,1]:=u; pre[v,2]:=e;
 55     dis[v]:=dis[u]+len2[e];
 56     if not inq[v] then
 57     begin
 58      inc(w); q[w mod (s+5)]:=v;
 59      inq[v]:=true;
 60     end;
 61    end;
 62    e:=next[e];
 63   end;
 64  end;
 65  if dis[src]=-maxlongint then exit(false)
 66   else exit(true);
 67 end;
 68
 69 procedure mcf;
 70 var k,e:longint;
 71     t:int64;
 72 begin
 73  k:=src; t:=maxlongint;
 74  while k<>source do
 75  begin
 76   e:=pre[k,2]; k:=pre[k,1];
 77   t:=min(t,len1[e]);
 78  end;
 79  k:=src;
 80  while k<>source do
 81  begin
 82   e:=pre[k,2];
 83   len1[e]:=len1[e]-t;
 84   len1[fan[e]]:=len1[fan[e]]+t;
 85   ans:=ans+t*len2[e];
 86   k:=pre[k,1];
 87  end;
 88 end;
 89
 90 begin
 91  assign(input,‘codevs1227.in‘); reset(input);
 92  assign(output,‘codevs1227.out‘); rewrite(output);
 93  readln(n,k1);
 94  for i:=1 to 200000 do
 95   if i mod 2=1 then fan[i]:=i+1
 96    else fan[i]:=i-1;
 97  for i:=1 to n do
 98   for j:=1 to n do read(a[i,j]);
 99  for i:=1 to n do
100   for j:=1 to n do
101    for k:=1 to 2 do
102    begin
103     inc(s); num[i,j,k]:=s;
104    end;
105  for i:=1 to n do
106   for j:=1 to n do
107   begin
108    add(num[i,j,1],num[i,j,2],1,a[i,j]);
109    add(num[i,j,1],num[i,j,2],k1,0);
110    if j+1<=n then add(num[i,j,2],num[i,j+1,1],k1,0);
111    if i+1<=n then add(num[i,j,2],num[i+1,j,1],k1,0);
112   end;
113  source:=1; src:=s+1; inc(s);
114  add(num[n,n,2],src,k1,0);
115  while spfa do mcf;
116  writeln(ans);
117  close(input);
118  close(output);
119 end.
时间: 2024-10-05 21:46:20

【Codevs1227】方格取数2(费用流)的相关文章

Luogu1006 传纸条 与 Luogu P2045方格取数加强版 (费用流)

Luogu1006 传纸条 与 Luogu P2045方格取数加强版 其实就是这几道题 在一个有m*n 个方格的棋盘中 每个方格中有一个正整数 现要从在方格中从左上角到右下角取数,只能向右或向下走 每走到一个格子就可以把这个位置上的数取走(下次经过就没有了) 1.让你走1次,求取出的数的总和最大是多少 2.让你走2次,求取出的数的总和最大是多少 3.让你走k次,求取出的数的总和最大是多少 对于第一问,十分显然. 设\(f[i][j]\)表示\(i\)行\(j\)列的最大价值,转移即可. 第二问,

[CodeVs1227]方格取数2(最大费用最大流)

网络流24题的坑还没填完就来搞其他题,你真的要TJ? 写这题给自己的费用流攒个模板. 题目大意:一个n*n的矩阵,每格有点权,从(1,1)出发,可以往右或者往下走,最后到达(n,n),每达到一格,把该格子的数取出来,该格子的数就变成0,这样一共走K次,现在要求K次所达到的方格的数的和最大. 啊简单的费用流.每个点i拆成i和i',连一条容量为1的边价值为点权,再连一条容量inf的边价值为0来让这个点能被经过,然后S连(1,1)容量k价值0,i'和右.下的点连容量inf价值0的边,(n,n)'连T容

hdu1565方格取数(1) 最大流之 最大点权独立集

//给一个n*n的矩阵,问从这个矩阵中若干数,这些数不相邻 //问这些数的最大值为多少 //1. 最小点权覆盖集=最小割=最大流 //2. 最大点权独立集=总权-最小点权覆盖集 //将(i+j)%2 == 1分为x集,将(i+j)%2==0分为y集 //对x集向y集相邻的边引入权值为inf的边 //源点向x集引入权值为该点权值的边 , 从y集向汇点引入权值为该点权值的边 //那么答案是其最大点权独立集 #include<cstdio> #include<cstring> #incl

NEU 1458 方格取数(网络流之费用流)

题目地址:NEU 1458 跟杭电上的那两个方格取数不太一样..这个可以重复,但是取和的时候只能加一次.建图思路基本一会就出来.同样的拆点,只不过这题需要再拆个边,其中一条费用0,另一条费用为那个点处的值.流量都限制为1.然后剩下的都跟杭电上的那两个差不多了.因为把数组开小了WA了好几发..(我前面居然还专门检查了一下数组大小,居然当时还认为没开小...对自己无语..) 代码如下: #include <iostream> #include <stdio.h> #include &l

HDU 3376 &amp;&amp; 2686 方格取数 最大和 费用流裸题

题意: 1.一个人从[1,1] ->[n,n] ->[1,1] 2.只能走最短路 3.走过的点不能再走 问最大和. 对每个点拆点限流为1即可满足3. 费用流流量为2满足1 最大费用流,先给图取负,结果再取负,满足2 #include <stdio.h> #include <string.h> #include <iostream> #include <math.h> #include <queue> #include <set&

HDU 1565&amp;1569 方格取数系列(状压DP或者最大流)

方格取数(2) Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 6206    Accepted Submission(s): 1975 Problem Description 给你一个m*n的格子的棋盘,每个格子里面有一个非负数. 从中取出若干个数,使得任意的两个数所在的格子没有公共边,就是说所取数所在的2个格子不能相邻,并且取出的

hdu1565方格取数(1)【最大流||最大点权独立集】

Problem Description 给你一个n*n的格子的棋盘,每个格子里面有一个非负数.从中取出若干个数,使得任意的两个数所在的格子没有公共边,就是说所取的数所在的2个格子不能相邻,并且取出的数的和最大. Input 包括多个测试实例,每个测试实例包括一个整数n 和n*n个非负数(n<=20) Output 对于每个测试实例,输出可能取得的最大的和 Sample Input 3 75 15 21 75 15 28 34 70 5 Sample Output 188 预备知识: 对于一个无向

hdoj 1569 方格取数 【最大点权独立集-&gt;最大流】

题目:hdoj 1569 方格取数 题意:中文题目,就不说题意了. 分类:最大流 |  dp 分析:dp的话应该是个数塔模型,不难做,这里讲转化为图的做法. 这个题目的关键在于转化为一个二分图,来求一个二分图的最大点权独立集,而最大点权独立集 = 点权和 - 最小点权覆盖 最小点权覆盖: 从x或者y集合中选取一些点,使这些点覆盖所有的边,并且选出来的点的权值尽可能小. 最大点权独立集:找到二分图中权值和最大的点集,然后让任意点没有边. 而最小点权覆盖 = 最小割 = 最大流 = sum - 最大

734. [网络流24题] 方格取数问题 二分图点权最大独立集/最小割/最大流

?问题描述:在一个有m*n 个方格的棋盘中,每个方格中有一个正整数.现要从方格中取数,使任意2 个数所在方格没有公共边,且取出的数的总和最大.试设计一个满足要求的取数算法.?编程任务:对于给定的方格棋盘,按照取数要求编程找出总和最大的数.?数据输入:由文件grid.in提供输入数据.文件第1 行有2 个正整数m和n,分别表示棋盘的行数和列数.接下来的m行,每行有n个正整数,表示棋盘方格中的数. [问题分析] 二分图点权最大独立集,转化为最小割模型,从而用最大流解决. [建模方法] 首先把棋盘黑白

LiberOJ #6007. 「网络流 24 题」方格取数 最小割 最大点权独立集 最大流

#6007. 「网络流 24 题」方格取数 内存限制:256 MiB时间限制:1000 ms标准输入输出 题目类型:传统评测方式:文本比较 上传者: 匿名 提交提交记录统计讨论测试数据 题目描述 在一个有 m×n m \times nm×n 个方格的棋盘中,每个方格中有一个正整数. 现要从方格中取数,使任意 2 22 个数所在方格没有公共边,且取出的数的总和最大.试设计一个满足要求的取数算法. 输入格式 文件第 1 11 行有 2 22 个正整数 m mm 和 n nn,分别表示棋盘的行数和列数