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

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


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

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 care that the rook moves only to the right or down. Kaka adds the number to SUM in each grid the rook visited, and replaces it with zero. It is not difficult to know the maximum SUM Kaka can obtain for his first travel. Now Kaka is wondering what is the maximum SUM he can obtain after his Kth travel. Note the SUM is accumulative during the K travels.

Input

The first line contains two integers N and K (1 ≤ N ≤ 50, 0 ≤ K ≤ 10) described above. The following N lines represents the matrix. You can assume the numbers in the matrix are no more than 1000.

Output

The maximum SUM Kaka can obtain after his Kth travel.

Sample Input

3 2
1 2 3
0 2 1
1 4 2

Sample Output

15

Source

POJ Monthly--2007.10.06, Huang, Jinsong

流这东西真是。。啥东西都可以拿来做……

一眼看上去很有dp的冲动……如果单次是个裸dp,但这里设定从左上走到右下 走k次 每次经过的点的价值会加入总价值 并把这些点的价值更新为0

可能没怎么做过流的题 很艰难的往最小费上套……要不是训练计划分到了那里面。。。我应该是想不到的

要求只能往下或右走 这样在所有满足的点之间加一个弧跟反向弧

由于每个点要限制只有一次能获得点权 这样就需要进行拆点 把点一分为二 分开后在两个点间连一个费用为点权 流量1的边跟一个费用0流量k-1的点 就相当于在这个点内部加了限制 

之后将超源跟最左上角点连接 费用0 流量k 最右下角点跟超汇连 费用0 流量k


代码如下:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <queue>

using namespace std;
const int INF = 0x3f3f3f3f;

struct Edge
{
    int v,cup,cost,next;
    Edge(){}
    Edge(int _v,int _cup,int _cost,int _next):v(_v),cup(_cup),cost(_cost),next(_next){}
};

//邻接表建图
Edge eg[233333];
int head[5555];
int tp;
//最小费广搜
int cur[5555],dis[5555];
bool vis[5555];
//超源 超汇 点个数 走的次数 总花费
int st,en,n,k,cost;

void init()
{
    memset(head,-1,sizeof(head));
    tp = st = cost = 0;
    en = 2*n*n+1;
}

void Add(int u,int v,int cup,int cost)
{
    eg[tp] = Edge(v,cup,cost,head[u]);
    head[u] = tp++;
    eg[tp] = Edge(u,0,-cost,head[v]);
    head[v] = tp++;
}

bool spfa()
{
    //puts("**********");
    memset(dis,-1,sizeof(dis));
    memset(vis,0,sizeof(vis));
    cur[en] = cur[st] = -1;
    queue <int> q;
    q.push(st);
    vis[st] = 1;
    dis[st] = 0;
    int minflow = INF;

    while(!q.empty())
    {
        int u = q.front();
        q.pop();
        vis[u] = 0;
        for(int i = head[u]; i != -1; i = eg[i].next)
        {
            int v = eg[i].v;
            if(dis[v] < dis[u]+eg[i].cost && eg[i].cup)
            {
                minflow = min(minflow,eg[i].cup);
                dis[v] = dis[u]+eg[i].cost;
            //printf("%d %d %d %d\n",u,v,eg[i].cost,dis[v]);
                cur[v] = i;
                if(!vis[v])
                {
                    q.push(v);
                    vis[v] = 1;
                }
            }
        }
    }

    if(dis[en] <= 0) return 0;

    cost += dis[en];
    //printf("%d\n",cost);
    for(int i = cur[en]; i != -1; i = cur[eg[i^1].v])
    {
        //printf("%d\n",eg[i].v);
        eg[i].cup -= minflow;
        eg[i^1].cup += minflow;
    }
    //puts("---------");
    return 1;
}

int main()
{
    int w,id;
    scanf("%d %d",&n,&k);

    init();
    for(int i = 0; i < n; ++i)
    {
        for(int j = 1; j <= n; ++j)
        {
            id = i*n+j;
            scanf("%d",&w);
            Add(id*2-1,id*2,1,w);
            Add(id*2-1,id*2,k-1,0);
            //not left
            if(j != 1) Add((id-1)*2,id*2-1,k,0);
            //not right
            if(i) Add((id-n)*2,id*2-1,k,0);
        }
    }
    
    //超源->1
    Add(0,1,k,0);
    //n*n*2->超汇
    Add(2*n*n,2*n*n+1,k,0);
    
    while(spfa());
    printf("%d\n",cost);
    return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值