POJ 3422 Kaka's Matrix Travels (K取方格数:最大费用流)
题意
给出一个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取方格数:最大费用流)的更多相关文章
- POJ 3422 Kaka's Matrix Travels K取方格数
题目:给出n*n的方格矩阵,现在从左上方走m次到右下方,问m次能够获得的最大价值和. 分析:最大费用流.拆点进行限制每个格子只取一次,假设点x拆成 x,xx,右边(假设有)y,yy,下方(假设有)z, ...
- Luogu2045 方格取数加强版(K取方格数) 费用流
题目传送门 题意:给出一个$N \times N$的方格,每个格子中有一个数字.你可以取$K$次数,每次取数从左上角的方格开始,每一次只能向右或向下走一格,走到右下角结束,沿路的方格中的数字将会被取出 ...
- POJ 3422 Kaka's Matrix Travels
Kaka's Matrix Travels Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 9567 Accepted: ...
- POJ 3422 Kaka's Matrix Travels(费用流)
Kaka's Matrix Travels Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 6792 Accepted: ...
- poj 3422 Kaka's Matrix Travels 费用流
题目链接 给一个n*n的矩阵, 从左上角出发, 走到右下角, 然后在返回左上角,这样算两次. 一共重复k次, 每个格子有值, 问能够取得的最大值是多少, 一个格子的值只能取一次, 取完后变为0. 费用 ...
- [poj] 3422 Kaka's Matrix Travels || 最小费用最大流
原题 给一个N*N的方阵,从[1,1]到[n,n]走K次,走过每个方格加上上面的数,然后这个格上面的数变为0.求可取得的最大的值. 要求最大值,所以把边权全为负跑最小费用即可.因为只有第一次经过该点的 ...
- POJ 3422 Kaka's Matrix Travels(最小费用最大流)
http://poj.org/problem?id=3422 题意 : 给你一个N*N的方格,每个格子有一个数字,让你从左上角开始走,只能往下往右走,走过的数字变为0,走K次,问最大能是多大,累加的. ...
- POJ 3422 Kaka's Matrix Travels 【最小费用最大流】
题意: 卡卡有一个矩阵,从左上角走到右下角,卡卡每次只能向右或者向下.矩阵里边都是不超过1000的正整数,卡卡走过的元素会变成0,问卡卡可以走k次,问卡卡最多能积累多少和. 思路: 最小费用最大流的题 ...
- POJ 3422 Kaka's Matrix Travels(拆点+最大费用流)题解
题意:小A从左上角走到右下角,每个格子都有一个价值,经过这个格子就把价值拿走,每次只能往下或往右走,问你走k次最多能拿多少价值的东西. 思路:这里有一个限制条件就是经过之后要把东西拿走,也就是每一格的 ...
随机推荐
- POJ 3279
Fliptile Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 3062 Accepted: 1178 Descript ...
- POJ 2227 The Wedding Juicer (优先级队列+bfs+dfs)
思路描述来自:http://hi.baidu.com/perfectcai_/item/701f2efa460cedcb0dd1c820也可以参考黑书P89的积水. 题意:Farmer John有一个 ...
- 【C语言】二维数组做形参
二维数组有两种形式: ①在栈上: int a[4][4] = {...}; ②在堆堆上: int ** a = new int *[4]; for ...
- linux查看硬件信息及驱动设备相关整理
查看声卡设备:cat /proc/asound/cards 查看USB设备:cat /proc/bus/usb/devices 常用命令整理如下:用硬件检测程序kuduz探测新硬件:service k ...
- Shell实现跳板机,为什么用跳板机
整理自:http://blog.chinaunix.net/uid-22101889-id-3167454.html 注意:请谨慎使用,到现在为止,使用了,我还没找到改回去的方法. 1. 问题 ...
- lightoj 1397 - Sudoku Solver
思路:每次找出可能情况最少的位置枚举可能情况!!! poj2676和这题一样不过poj数据比较水,很容易过. 代码如下: #include<iostream> #include<cs ...
- 解决xshell连接linux总是异常断开的问题?
找到etc下面的profile文件,可以看到有下面一行: TMOUT=;export TMOUT 注释掉即可解决. #TMOUT=;export TMOUT
- Delphi是座宝山,有待挖掘
Delphi是座宝山,有待挖掘1. VCL源码是座宝山,把纷繁复杂的Windows编程封装到短短几个类里,不超过8000行代码,还额外包括许多其它的技巧2. RTL是座宝山,方便程序员使用底层运算,不 ...
- Hibernate笔记——第一个简单实例
1. 首先进行框架配置 导包 hibernate配置xml文件 ======================= 2. 创建并配置POJO类 Hibernate是操作持久化层的框架,和数据库打交道,其 ...
- Android:开发环境
一.JAVA SDK(JDK)的安装 http://www.cnblogs.com/tinyphp/p/3664598.html 二.ADT-Bundle 包含了Eclipse.ADT插件和SDK T ...