【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;
}



你可能感兴趣的:(【POJ 3422】 Kaka's Matrix Travels (最小费用最大流))