题目链接:http://acm.hit.edu.cn/hoj/problem/view?id=2715

Time limit : 5 sec Memory limit : 64 M

Zhouguyue is a "驴友" and nowadays he likes traveling on an N * N matrix with a non-negative number in each grid, and each grid has a height. Zhouguyue starts his matrix travel with POINT = 0. For each travel, zhouguyue can land on any grid he wants with the help of bin3's helicopter, and then he can only move to ajacent grids whose height is less than his current height. Notice that when he is at the side of the matrix, he can also move out of the matrix. After he moves out of the matrix, he completes one travel. He adds the number in each grid he visited to POINT, and replaces it with zero. Now zhouguyue is wondering what is the maximum POINT he can obtain after he travels at most K times. Note the POINT is accumulative during the travels.

Input

The first line is a integer T indicating the number of test cases.T cases fllows. The first line of each case contains two integers N and K (1 ≤ N ≤ 50, 0 ≤ K ≤ 50) described above. The following N lines represents the matrix. You can assume the numbers in the matrix are non-negative integers and no more than 10000. The following N lines represents the height of each grid. The heghts are also non-negative integers.

Output

The maximum POINT zhouguyue can obtain after he travels at most K times.

Sample Input

1
3 2
1 2 3
3 2 1
2 4 2 3 5 3
2 1 0
1 2 3

Sample Output

17

题意:

一个 N*N 的网格,每个单元都有一个数字number[i][j],和一个高度height[i][j]。

现在 ZhouGuyue 要作至多 K 次旅行,每次旅行如下:

他可以借助 bin3 的直升机飞到 任意一个单元格,之后他每次只能向相邻的且高度比当前所在格子低的格子移动。

当他移动到一个边界的格子上时,他可以跳出这个网格并完成一次旅行。

旅行开始前,他有一个POINT,初始值为0;旅行途中,所到的每一格的number[i][j]可以加到他的POINT里,一旦加上,格子里number[i][j]就变成0。

问POINT最大有多大。(1 <= N <= 50, 0 <= K <= 50, 0 <= Vi <= 10000)

解题思路:

本题属于最大费用最大流问题,对cost取负后转变成为最小费用最大流问题,构图完成后可以直接上模板,最后求出mincost再取个负即为答案。

构图:

将每个格子 i 进行拆点,并加边(i’, i’’, 1,  -number[i]), (i’, i’’, ∞, 0), (s, i’, ∞, 0);(分别对应from,to,cap,cost)

  这代表,他走第一次,可以走(i’, i’’, 1,  -number[i]),由于算法保证最小费用,他也只会先走(i’, i’’, 1,  -number[i]);

  走过这个格子,可以得到number,然后后面虽然可以继续走这个格子,但只能通过(i’, i’’, ∞, 0)这条边走,就得不到number;

  另外,由于他可以从任意格子出发,故要建立超级源点s,连接每个格子。

对相邻的四个格子 j,若 Hi > Hj 则加边(i’’, j’, ∞, 0);

  这条边很简单,代表可以同行,并且想走多少次都可以。

若格子 i在边界上则加边(i’’, t, ∞, 0);

  代表走到边界,可以直接结束本次旅行,由于边界上有许多格子,故也要建立超级汇点。

限制增广次数小于等于 K 。

  有增广一次可以看做沿某个路线走了一遍,并且获得了沿途的每个格子的number,增广次数不超过K,即代表旅行次数最多为K。

注意要点:

HIT的OJ可能卡STL,使用vector做邻接表超时(然后就只好自己写数组模拟邻接表呗,不过改一下也挺快,没啥问题);

如果使用的是刘汝佳书上的MCMF模板,while(spfa())语句增加限制次数K要注意写法,我就是没考虑到K==0的情况,刚开始写挫了,WA了一发;

代码:

 #include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
#define MAXN 2*53*53
#define MAXM 8*MAXN
#define INF 0x3f3f3f3f
#define in(x) x
#define out(x) x+n
using namespace std;
int n,N,K;
struct Edge{
int u,v,c,f,a;
};
struct MCMF
{
int s,t,ne;
Edge E[MAXM];
int head[MAXN],next[MAXM];
int vis[MAXN];
int d[MAXN];
int pre[MAXN];
int aug[MAXN];
void init()
{
ne=;
memset(head,-,sizeof(head));
}
void addedge(int from,int to,int cap,int cost)
{
E[ne].u=from, E[ne].v=to, E[ne].c=cap, E[ne].f=, E[ne].a=cost;
next[ne]=head[from]; head[from]=ne++;
E[ne].u=to, E[ne].v=from, E[ne].c=, E[ne].f=, E[ne].a=-cost;
next[ne]=head[to]; head[to]=ne++;
}
bool SPFA(int s,int t,int &flow,int &cost)
{
memset(d,INF,sizeof(d));
memset(vis,,sizeof(vis));
d[s]=, vis[s]=, pre[s]=, aug[s]=INF;
queue<int> q;
q.push(s);
while(!q.empty())
{
int now=q.front(); q.pop();
vis[now]=;
for(int i=head[now];i!=-;i=next[i])
{
Edge& e=E[i];
int nex=e.v;
if(e.c>e.f && d[nex]>d[now]+e.a)
{
d[nex]=d[now]+e.a;
pre[nex]=i;
aug[nex]=min(aug[now],e.c-e.f);
if(!vis[nex])
{
q.push(nex);
vis[nex]=;
}
}
}
}
if(d[t]==INF) return ;
flow+=aug[t];
cost+=d[t]*aug[t];
for(int i=t;i!=s;i=E[pre[i]].u)
{
E[pre[i]].f+=aug[t];
E[pre[i]^].f-=aug[t];
}
return ;
}
int mincost()
{
int flow=,cost=,cnt=;
while(cnt<K && SPFA(s,t,flow,cost)) cnt++;
return cost;
}
}mcmf; int number[][],height[][];
int d[][]={{,},{,},{,-},{-,}};
int inmap(int i,int j)
{
if(<=i && i<=N && <=j && j<=N) return (i-)*N+j;
else return ;
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&N,&K);
for(int i=;i<=N;i++) for(int j=;j<=N;j++) scanf("%d",&number[i][j]);
for(int i=;i<=N;i++) for(int j=;j<=N;j++) scanf("%d",&height[i][j]);
n=N*N;
mcmf.init();
mcmf.s=, mcmf.t=*n+;
for(int i=;i<=N;i++)
{
for(int j=;j<=N;j++)
{
int id=(i-)*N+j;
mcmf.addedge(mcmf.s,in(id),INF,);
mcmf.addedge(in(id),out(id),,-number[i][j]);
mcmf.addedge(in(id),out(id),INF,);
if(i== || i==N || j== || j==N) mcmf.addedge(out(id),mcmf.t,INF,);
for(int k=;k<;k++)
{
int nex_i=i+d[k][], nex_j=j+d[k][],nex_id;
if((nex_id=inmap(nex_i,nex_j)) && height[i][j]>height[nex_i][nex_j]) mcmf.addedge(out(id),in(nex_id),INF,);
}
}
}
printf("%d\n",-mcmf.mincost());
}
}

HIT 2715 - Matrix3 - [最小费用最大流][数组模拟邻接表MCMF模板]的更多相关文章

  1. 最小费用最大流 学习笔记&&Luogu P3381 【模板】最小费用最大流

    题目描述 给出一个网络图,以及其源点和汇点,每条边已知其最大流量和单位流量费用,求出其网络最大流和在最大流情况下的最小费用. 题目链接 思路 最大流是没有问题的,关键是同时保证最小费用,因此,就可以把 ...

  2. SDUT OJ 图练习-BFS-从起点到目标点的最短步数 (vector二维数组模拟邻接表+bfs , *【模板】 )

    图练习-BFS-从起点到目标点的最短步数 Time Limit: 1000ms   Memory limit: 65536K  有疑问?点这里^_^ 题目描述 在古老的魔兽传说中,有两个军团,一个叫天 ...

  3. HIT 2739 - The Chinese Postman Problem - [带权有向图上的中国邮路问题][最小费用最大流]

    题目链接:http://acm.hit.edu.cn/hoj/problem/view?id=2739 Time limit : 1 sec Memory limit : 64 M A Chinese ...

  4. 【BZOJ】1221: [HNOI2001] 软件开发(最小费用最大流)

    http://www.lydsy.com/JudgeOnline/problem.php?id=1221 先吐槽一下,数组依旧开小了RE:在spfa中用了memset和<queue>的版本 ...

  5. 最小费用最大流 POJ2195-Going Home

    网络流相关知识参考: http://www.cnblogs.com/luweiseu/archive/2012/07/14/2591573.html 出处:優YoU http://blog.csdn. ...

  6. hdu-3376-Matrix Again(最小费用最大流)

    题意: 给一个矩形,从左上角走到右下角,并返回左上角(一个单元格只能走一次,左上角和右下角两个点除外) 并且从左上到右下只能往右和下两个方向.从右下返回左上只能走上和左两个方向! 分析: 拆点,最小费 ...

  7. Luogu P3381 (模板题) 最小费用最大流

    <题目链接> 题目大意: 给定一张图,给定条边的容量和单位流量费用,并且给定源点和汇点.问你从源点到汇点的最带流和在流量最大的情况下的最小费用. 解题分析: 最小费用最大流果题. 下面的是 ...

  8. 经典贪心算法(哈夫曼算法,Dijstra单源最短路径算法,最小费用最大流)

    哈夫曼编码与哈夫曼算法 哈弗曼编码的目的是,如何用更短的bit来编码数据. 通过变长编码压缩编码长度.我们知道普通的编码都是定长的,比如常用的ASCII编码,每个字符都是8个bit.但在很多情况下,数 ...

  9. [BZOJ2055]80人环游世界 有上下界最小费用最大流

    2055: 80人环游世界 Time Limit: 10 Sec  Memory Limit: 64 MB Description     想必大家都看过成龙大哥的<80天环游世界>,里面 ...

随机推荐

  1. 禁用ViewPager左右两侧拉到边界的渐变颜色

    Android ViewPager在拖拽到左边和右边的时候,禁止显示黄色或者蓝色的渐变图片的解决方法 先说明哦,想看看院里的,从头开始看,否则,就拉到最下面啦.解决方案就在最下面. 修改前: 修改后: ...

  2. flexbox常用布局左右固定,中间自适应

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name ...

  3. iOS开发-UIImageView响应点击事件

    UIImageView是不能够响应点击事件的,在开发过程中我们需要经常对头像等添加点击事件,上网搜索一番后发现有如下两个方法: 1.找到点击图片Event,添加事件处理函数 UIImageView.u ...

  4. iOS开发-iOS7禁用手势返回

    - (void)viewDidAppear:(BOOL)animated { [super viewDidAppear:animated]; // 禁用 iOS7 返回手势 if ([self.nav ...

  5. error:1407742E:SSL routines:SSL23_GET_SERVER_HELLO:tlsv1 alert protocol version

    更新的软件可以解决 TortoiseGit-preview-2.5.7.0-20180127-b2d00f8-64bit.msi和Git-2.16.2-64-bit.exe. 链接地址为: https ...

  6. jQuery ajax中serialize()方法增加其他参数

    表单提交 使用jQuery.ajax()进行表单提交时,需要传递参数,最直接的方法便是使用Form的serializa()将表单序列化,前提只是将Form表单中的name属性与数据库的字段名保持一致便 ...

  7. 通过java的i/o机制进行图片流的存储以及对网络图片的存储

    存储内地图片思路:首先把原有的图片以流的方式读取出来,再以流的方式存储到目标文件: package imgStream; import java.io.*; public class ImgStrea ...

  8. <转>Python: __init__.py 用法

    转自 http://www.cnblogs.com/BeginMan/p/3183629.html python的每个模块的包中,都有一个__init__.py文件,有了这个文件,我们才能导入这个目录 ...

  9. Android SDK更新8.1.0时报错

    Done loading packages.Preparing to install archivesDownloading SDK Platform Android 8.1.0, API 27, r ...

  10. 深入学习Make命令和Makefile(下)

    https://www.zybuluo.com/lishuhuakai/note/209300 make是Linux下的一款程序自动维护工具,配合makefile的使用,就能够根据程序中模块的修改情况 ...