题意

给出一个n*n大小的矩阵,要求从左上角走到右下角,每次只能向下走或者向右走并取数,某位置取过数之后就只为数值0,现在求解从左上角到右下角走K次的最大值.

思路

经典的费用流模型:K取方格数。

构图方法:将矩阵的每个元素m[i][j]拆成两个点u=(i-1)*n+j和v=n*n+(i-1)*n+j,从u到v连两条边:
1> 连边(u,v),容量为1,费用值为m[i][j],这样可以保证每一个位置的数只被取一次
2> 连边(u,v),容量为INF,费用值为0,这样可以保证某位置取数被置为0之后,随便怎么取对最后的费用值不会产生影响
由于每次只能向下走或者向右走,所以需要连两条边:
1> 向下走:即从(i,j)到(i+1,j),连边v=n*n+(i-1)*n+j到i*n+j,容量为INF,费用为0
2> 向右走:即从(i,j)到(i,j+1),连边v=n*n+(i-1)*n+j到(i-1)*n+j+1,容量为INF,费用为0.
然后为了限制只走K次,需要添加源点s=0和汇点t=2*n*n+1,连边:s……矩阵左上角顶点1,容量为k,费用为0,连边矩阵右下角顶点被拆之后对应的顶点2*n*n……t,容量为K,费用为0,然后对所建立的图求解最大费用流即可.

代码

[cpp]
#include <iostream>
#include <cstdio>
#include <cmath>
#include <vector>
#include <algorithm>
#include <string>
#include <queue>
#include <cstring>
#define MID(x,y) ((x+y)/2)
#define MEM(a,b) memset(a,b,sizeof(a))
#define REP(i, begin, m) for (int i = begin; i < begin+m; i ++)
using namespace std;

const int MAXV = 200005;
const int MAXE = 100005;
const int oo = 0x3fffffff;

template <class NodesType>
struct Nodes{
NodesType dist;
int pre, head; //pre存前趋边, head存前向星
bool visit;
};
template <class EdgesType>
struct Edges{
int u, v, next;
EdgesType cost, flow;
};
template <class T>
struct MinCostMaxFlow{
Nodes <T> node[MAXV];
Edges <T> arc[2*MAXE];
int vn, en;
void init(int n){
vn = n;
en = 0;
for (int i = 0; i <= n; i ++){
node[i].head = -1;
}
}
void insert_flow(int u, int v, T flow, T cost){
arc[en].u = u;
arc[en].v = v;
arc[en].flow = flow;
arc[en].cost = cost;
arc[en].next = node[u].head;
node[u].head = en ++;
arc[en].v = u;
arc[en].u = v;
arc[en].flow = 0;
arc[en].cost = -cost;
arc[en].next = node[v].head;
node[v].head = en ++;
}
void print_edges(){
for (int i = 0; i < en; i ++){
printf("u = %d v = %d flow = %d cost = %d\n", arc[i].u, arc[i].v, arc[i].flow, arc[i].cost);
}
}
queue <int> q;
bool spfa(int s, int t){
for (int i = 1; i <= vn; i ++){
node[i].dist = oo;
node[i].pre = -1;
node[i].visit = false;
}
node[s].dist = 0;
node[s].visit = true;
q.push(s);
while(!q.empty()){
int u = q.front();
q.pop();
node[u].visit = false;
for (int i = node[u].head; i != -1; i = arc[i].next){
int v = arc[i].v;
if (arc[i].flow > 0 && node[v].dist > node[u].dist + arc[i].cost){
node[v].dist = node[u].dist + arc[i].cost;
node[v].pre = i;
if (!node[v].visit){
node[v].visit = true;
q.push(v);
}
}
}
}
if (node[t].pre == -1)
return 0;
else
return 1;
}
T solve(int s, int t, T &mincost){
mincost = 0;
T maxflow = 0;
while(spfa(s, t)){
T minflow = oo;
for (int i = node[t].pre; i != -1; i = node[arc[i].u].pre){
minflow = min(minflow, arc[i].flow);
}
for (int i = node[t].pre; i != -1; i = node[arc[i].u].pre){
arc[i].flow -= minflow;
arc[i^1].flow += minflow;
mincost += arc[i].cost * minflow;
}
maxflow += minflow;
}
return maxflow;
}
};
MinCostMaxFlow <int> mcmf;

int map[55][55];
int main(){
//freopen("test.in", "r", stdin);
//freopen("test.out", "w", stdout);
int n, k;
while(scanf("%d %d", &n, &k) != EOF){
mcmf.init(2*n*n+2);
mcmf.insert_flow(2*n*n+1, 1, k, 0);
mcmf.insert_flow(2*n*n, 2*n*n+2, k, 0);
REP(i, 1, n)
REP(j, 1, n){
scanf("%d", &map[i][j]);
int u = (i-1)*n+j;
mcmf.insert_flow(u, u+n*n, 1, -map[i][j]);
mcmf.insert_flow(u, u+n*n, oo, 0);
if (i < n){
mcmf.insert_flow(u+n*n, u+n, oo, 0);
}
if (j < n){
mcmf.insert_flow(u+n*n, u+1, oo, 0);
}
}
//mcmf.print_edges();
int res = 0;
mcmf.solve(2*n*n+1, 2*n*n+2, res);
printf("%d\n", -res);
}
return 0;
}
[/cpp]

POJ 3422 Kaka's Matrix Travels (K取方格数:最大费用流)的更多相关文章

  1. POJ 3422 Kaka's Matrix Travels K取方格数

    题目:给出n*n的方格矩阵,现在从左上方走m次到右下方,问m次能够获得的最大价值和. 分析:最大费用流.拆点进行限制每个格子只取一次,假设点x拆成 x,xx,右边(假设有)y,yy,下方(假设有)z, ...

  2. Luogu2045 方格取数加强版(K取方格数) 费用流

    题目传送门 题意:给出一个$N \times N$的方格,每个格子中有一个数字.你可以取$K$次数,每次取数从左上角的方格开始,每一次只能向右或向下走一格,走到右下角结束,沿路的方格中的数字将会被取出 ...

  3. POJ 3422 Kaka's Matrix Travels

    Kaka's Matrix Travels Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 9567   Accepted:  ...

  4. POJ 3422 Kaka's Matrix Travels(费用流)

    Kaka's Matrix Travels Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 6792   Accepted:  ...

  5. poj 3422 Kaka's Matrix Travels 费用流

    题目链接 给一个n*n的矩阵, 从左上角出发, 走到右下角, 然后在返回左上角,这样算两次. 一共重复k次, 每个格子有值, 问能够取得的最大值是多少, 一个格子的值只能取一次, 取完后变为0. 费用 ...

  6. [poj] 3422 Kaka's Matrix Travels || 最小费用最大流

    原题 给一个N*N的方阵,从[1,1]到[n,n]走K次,走过每个方格加上上面的数,然后这个格上面的数变为0.求可取得的最大的值. 要求最大值,所以把边权全为负跑最小费用即可.因为只有第一次经过该点的 ...

  7. POJ 3422 Kaka's Matrix Travels(最小费用最大流)

    http://poj.org/problem?id=3422 题意 : 给你一个N*N的方格,每个格子有一个数字,让你从左上角开始走,只能往下往右走,走过的数字变为0,走K次,问最大能是多大,累加的. ...

  8. POJ 3422 Kaka's Matrix Travels 【最小费用最大流】

    题意: 卡卡有一个矩阵,从左上角走到右下角,卡卡每次只能向右或者向下.矩阵里边都是不超过1000的正整数,卡卡走过的元素会变成0,问卡卡可以走k次,问卡卡最多能积累多少和. 思路: 最小费用最大流的题 ...

  9. POJ 3422 Kaka's Matrix Travels(拆点+最大费用流)题解

    题意:小A从左上角走到右下角,每个格子都有一个价值,经过这个格子就把价值拿走,每次只能往下或往右走,问你走k次最多能拿多少价值的东西. 思路:这里有一个限制条件就是经过之后要把东西拿走,也就是每一格的 ...

随机推荐

  1. 【四】php字符串操作

    1.trim函数,我们队trim函数并不陌生,用于去除字符串两头的空白符.php的trim方法也可以做到这一点,但是还可以使用第二个参数,用于规定你在两头去掉什么.php中还有 ltrim 和 rtr ...

  2. Appium下Android keyevent整理

    keycode 3:首页(Home key) keycode 4:返回键(Back key) keycode 5:电话键(Call key) keycode 6:结束通话键(End Call key) ...

  3. java与.net之间xml传递,xml最前面多了个?

    最近做一个项目,是java提供webservice供.net调用.参数采用xml格式.首先碰到的问题: 1).net这边采用XmlSerializer 方式序列化对象传递给对方.对方在本机调试可以收到 ...

  4. Android图片缩放方法

    安卓开发中应用到图片的处理时候,我们通常会怎么缩放操作呢,来看下面的两种做法: 方法1:按固定比例进行缩放 在开发一些软件,如新闻客户端,很多时候要显示图片的缩略图,由于手机屏幕限制,一般情况下,我们 ...

  5. Linux基础--文件压缩

    1.compress [root@linux ~]# compress [-dcr] 档案或目录 参数: -d:用来解压缩的参数 -r:可以连同目录下的档案也同时给予压缩呢! -c:将压缩数据输出成为 ...

  6. 《从零开始学习jQuery》及《jQuery风暴》学习笔记

    第一章 jQuery入门 1.用$()函数其实是一个事件,使用这个函数调用的方法,会在DOM加载完毕.资源文件加载完之前触发. 第二章 必须知道的JavaScript知识 1.JavaScript实际 ...

  7. 如何用crontab运行一个图形化界面的程序

    crontab是linux中定时任务的 执行crontab -e可以编辑定时列表(export DISPLAY=:0 指定显示器或者export DISPLAY=localhost:0) 15 13 ...

  8. Gravitational Teleport 是一个先进的 SSH 服务器,基于 Golang SSH 构建,完全兼容 OpenSSH

    Gravitational Teleport 是一个先进的 SSH 服务器,可通过 SSH 或者 HTTPS 远程访问 Linux 服务器.其目的是为了替代 sshd.Teleport 可以轻松让团队 ...

  9. CreateFile,WriteFile,ReadFile

    注意: CreateFile 跟 fopen 不同,打开文件时不区分 文本方式 或 二进制 方式 ReadFile 或 WriteFile 都是对二进制数据进行操作 HANDLE WINAPI Cre ...

  10. 开发ProxyServer的时候如何在一台PC上调试

    为了测试在真实的网络环境下你的ProxyServer性能如何,而你手头又只有一台电脑,怎么办? 打开你的ProxyServer(我用java写的,因此ProxyServer的进程是javaw.exe) ...