题目链接: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. iOS6 中 Smart App Banners介绍和使用(转自COCOACHINA.COM)

    转自:http://www.cocoachina.com/applenews/devnews/2012/0924/4842.html iOS 6新增Smart App Banners,也就是“智能Ap ...

  2. spray json, jackson 转到type时多key和少key的比较

    有组合关系的三个class定义 A { B { C {...} ... } ... } 每个class都有loadFromJson和writeAsJson方法.过去几年,三个class里的成员变量一直 ...

  3. vue中使用mockjs

    第一步安装mockjs:npm i mockjs -S 在src目录下新建mock文件夹,文件夹添加test.js test.js内容如下: import Mock from 'mockjs'; co ...

  4. 【Ubuntu】Windows 远程桌面连接ubuntu及xrdp的一些小问题(远程桌面闪退、连接失败、tab补全功能,无菜单栏,error - problem connecting )【转】

    转:https://blog.csdn.net/u014447845/article/details/80291678 1.远程桌面闪退,shell可以用的问题:(1)需要在该用户目录创建一个.xse ...

  5. PHP代码审计笔记--任意文件上传

     0x01 最简单的文件上传 未进行文件类型和格式做合法性校验,任意文件上传 漏洞代码示例: 新建一个提供上传文件的 upload.html <html> <body> < ...

  6. RF失败案例重跑

    1.1        失败案例重跑 该功能主要是针对上次连跑失败的案例需要重新执行测试的情况,可自动识别上次执行失败的案例并进行重跑,无需手动选择相应的案例,简单高效. 1.5.1.        重 ...

  7. Redis 集群配置

    Redis 集群介绍: (1) 为什么要使用集群:如果数据量很大,单台机器会存在存储空间不够用 .查询速度慢 .负载高等问题,部署集群就是为了解决这些问题(2) Redis 集群架构如下,采用无中心结 ...

  8. mybatis 之 parameterType="HashMap"参数包含list

    /** * 获得人气组合商品详情 * @param paramMap * @return */ public List<Goods> getCheckGoodsCombination(Ma ...

  9. Swift - 构造函数

    Swift 2.0 构造函数基础 构造函数是一种特殊的函数,主要用来在创建对象时初始化对象,为对象成员变量设置初始值,在 OC 中的构造函数是 initWithXXX,在 Swift 中由于支持函数重 ...

  10. IOS设计模式第八篇之键值观察模式

    版权声明:原创作品,谢绝转载!否则将追究法律责任. 键值观察模式: 在KVO,一个对象可以要求被通知当他的某个特殊的属性被改变了.自己或者另一个对象.如果你感兴趣你可以阅读更多的信息参考: Apple ...