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

POJ 3422 Kaka‘s Matrix Travels

链接:http://poj.org/problem?id=3422

题意:有一个N*N的方格,每个方格里面有一个数字。现在卡卡要从左上角走到右下角,规定每次只能向下或者向右走,每次走到一个格子,将得到该格子的数字,并且该格子的数字变为0。当卡卡走一次时,很容易求出最大值,问卡卡走k次,能够得到的最大值为多少。

思路:最小费用最大流

关键是如何构图

1. 将N*N个格点拆分为两个点(i,i + N*N),每个点之间连一条流量为1,费用为-w的边,再连一条流量为k,费用为0的边。这样就保证了每个点之间可以走k次,且最多只有一次能拿到费用。

2. 将每个点与其下面、右边的点连边,流量为k,费用为0.

3. 构造两个源点、汇点。源点和左上角连边,流量为k,费用为0. 右下角与汇点连边,流量为k,费用为0.

至此,容量网络已经构成。 每次在残余网络中找费用最短路进行增广即可。

代码:

/*
ID: [email protected]
PROG:
LANG: C++
*/
#include<map>
#include<set>
#include<queue>
#include<stack>
#include<cmath>
#include<cstdio>
#include<vector>
#include<string>
#include<fstream>
#include<cstring>
#include<ctype.h>
#include<iostream>
#include<algorithm>
using namespace std;
#define INF (1 << 20)
#define LINF (1LL << 60)
#define PI acos(-1.0)
#define mem(a, b) memset(a, b, sizeof(a))
#define rep(i, a, n) for (int i = a; i < n; i++)
#define per(i, a, n) for (int i = n - 1; i >= a; i--)
#define eps 1e-6
#define debug puts("===============")
#define pb push_back
#define mkp make_pair
#define all(x) (x).begin(),(x).end()
#define fi first
#define se second
#define SZ(x) ((int)(x).size())
#define POSIN(x,y) (0 <= (x) && (x) < n && 0 <= (y) && (y) < m)
typedef long long ll;
typedef unsigned long long ULL;
const int maxn = 5555;
const int maxm = 500000;
struct node {
    int v, cap, nxt, cost;
} e[maxm * 2];
int g[maxn], cnt, st, ed, n, m;
int ans, flow;
int nt, k;
void add(int u, int v, int cap, int cost) {
    e[++cnt].v = v;
    e[cnt].cap = cap;
    e[cnt].cost = cost;
    e[cnt].nxt = g[u];
    g[u] = cnt;

    e[++cnt].v = u;
    e[cnt].cap = 0;
    e[cnt].cost = -cost;
    e[cnt].nxt = g[v];
    g[v] = cnt;
}
void init() {
    cnt = 1;
    ans = flow = 0;
    memset(g, 0, sizeof(g));
    // 加边
    int w;
    int p = nt * nt;
    for (int i = 1; i <= nt; i++) {
        for (int j = 1; j <= nt; j++) {
            scanf("%d", &w);
            int id = (i - 1) * nt + j;
            add(id, id + p, 1, -w);
            add(id, id + p, k, 0);
            if (i < nt) add(id + p, id + nt, k, 0);
            if (j < nt) add(id + p, id + 1, k, 0);
        }
    }
    st = 0, ed = p * 2 + 1;
    n = ed;
    add(st, 1, k, 0);
    add(p * 2, ed, k, 0);
}

int dis[maxn], que[maxn], pre[maxn];
bool vis[maxn];
bool spfa() {
    int font = 0, rear = 1;
    for(int i = 0; i <= n; i ++) {
        dis[i] = INF;
        vis[i] = false;
    }
    dis[st] = 0;
    que[0] = st;
    vis[st] = true;
    while(rear != font) {
        int u = que[font++];
        font %= n;
        vis[u] = false;
        for(int i = g[u]; i; i = e[i].nxt) {
            int v = e[i].v;
            if(e[i].cap && dis[v] > dis[u] + e[i].cost) {
                dis[v] = dis[u] + e[i].cost;
                pre[v] = i;
                if(!vis[v]) {
                    vis[v] = true;
                    que[rear++] = v;
                    rear %= n;
                }
            }
        }
    }
    if(dis[ed] == INF) return false;
    return true;
}
void augment() {
    int u, p, mi = INF;
    for(u = ed; u != st; u = e[p ^ 1].v) {
        p = pre[u];
        mi = min(mi, e[p].cap);
    }
    for(u = ed; u != st; u = e[p ^ 1].v) {
        p = pre[u];
        e[p].cap -= mi;
        e[p ^ 1].cap += mi;
        ans += mi * e[p].cost;     //  cost记录的为单位流量费用,必须得乘以流量。
    }
    flow += mi;
}
int MCMF() {
    init();
    while(spfa()) augment();
    return ans;
}
int main () {
    while(~scanf("%d%d", &nt, &k)) {
        printf("%d\n", -MCMF());
    }
    return 0;
}

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

时间: 2024-08-01 17:53:03

POJ 3422 Kaka's Matrix Travels (最小费用最大流)的相关文章

POJ 3422 Kaka&#39;s Matrix Travels(费用流)

POJ 3422 Kaka's Matrix Travels 题目链接 题意:一个矩阵,从左上角往右下角走k趟,每次走过数字就变成0,并且获得这个数字,要求走完之后,所获得数字之和最大 思路:有点类似区间k覆盖的建图方法,把点拆了,每个点有值的只能选一次,其他都是无值的,利用费用流,入点出点之间连一条容量1,有费用的边,和一条容量k - 1,费用0的边,然后其他就每个点和右边和下边2个点连边,然后跑费用流 代码: #include <cstdio> #include <cstring&g

poj 3422 Kaka&#39;s Matrix Travels (费用流)

Kaka's Matrix Travels Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 7743   Accepted: 3111 Description On an N × N chessboard with a non-negative number in each grid, Kaka starts his matrix travels with SUM = 0. For each travel, Kaka mo

POj3422 Kaka&#39;s Matrix Travels 最小费用最大流 拆点

题目链接: poj3422 题意: 有一个N X N的矩阵, 矩阵的每一小格都有且仅有一个数字v,kaka每经过一个数字就会把它捡起来并将那个数字加到sum上去. 现在kaka能通过向下或向右走的方式从 (1,1)到(n,n)  K次,问kaka能取到的最大的sum是多少. 解题思路: 题目问题可以抽象为   求多次可走重复路的最长路的最大和问题 首先想到的就应该是最小费用最大流, 而题目要求的最大和值,那么应求就是最大费用最大流, 仅仅只需要将代码中的最小路算法改为最长路算法即可 题目的条件是

poj 3422 Kaka&#39;s Matrix Travels 最小费最大流

输入的时候没有取反,一直ole. 这里也是用到拆点,将一个点拆成p和q,这两个之间连接两条路,一条cap=1和cost=矩阵上的值,另一条为cap=k和cost=0.在将0和2*n *n+1看成源点和汇点. #include<stdio.h> #include<string.h> #include<vector> #include<queue> #include<algorithm> using namespace std; const int

POJ 3422 Kaka&#39;s Matrix Travels 【最小费用最大流】

题意: 卡卡有一个矩阵,从左上角走到右下角,卡卡每次只能向右或者向下.矩阵里边都是不超过1000的正整数,卡卡走过的元素会变成0,问卡卡可以走k次,问卡卡最多能积累多少和. 思路: 最小费用最大流的题目. 建图自己没想出来,看了大神的建边,把每个点分解成两个点,一个代表进入一个代表出去,然后每个进入和每个出去连边,容量是1价值是这个点的矩阵的数值.然后因为可以不进去,所以起点要和别的矩阵元素的起点建边,终点也要和别的矩阵矩阵元素的起点建边,最后跑下最小费用最大流. 这题最右下角的矩阵元素需要特殊

POJ 3422 Kaka&#39;s Matrix Travels(最大费用最大流 + 拆点)

题目链接:http://poj.org/problem?id=3422 Description On an N × N chessboard with a non-negative number in each grid, Kaka starts his matrix travels with SUM = 0. For each travel, Kaka moves one rook from the left-upper grid to the right-bottom one, taking

poj 3422 Kaka&#39;s Matrix Travels 【最大费用最大流】【好题】

Kaka's Matrix Travels Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 8729   Accepted: 3498 Description On an N × N chessboard with a non-negative number in each grid, Kaka starts his matrix travels with SUM = 0. For each travel, Kaka mo

poj 3422 Kaka&#39;s Matrix Travels 费用流

题意: 给一个n*n的矩阵,每次从左上角走到右下角并取走其中的数,求走k次能取到的最大和. 分析: 费用流边的容量有限制的作用,费用有求和的作用,对于每个点只能取一次,容易想到把这个点拆成两个点并连上容量为1,费用为该点数的边.但明显有的流要"跳过"这个点,如何处理呢?可以加一条容量为无穷,费用为0的边,这样不参加这点费用计算的流就可以"跳过"这个点了. 代码: //poj 3422 //sep9 #include <iostream> #include

POJ 3422 Kaka&#39;s Matrix Travels(网络流之费用流)

题目地址:POJ 3422 方法是对每个点i拆点成i'和i'',然后对每个i'和i''连一条费用为该点值,流量为1的边,再连1条费用为0,流量为k-1的边. 然后对每个点与右边下边相邻的点连边,流量均为INF,费用均为0.需要再建一源点与汇点,对于k次只需要在源点与汇点处进行限制即可. 代码如下: #include <iostream> #include <cstdio> #include <string> #include <cstring> #inclu