POJ 3422 Kaka's Matrix Travels 求最大流最“大”费用流

来源:互联网 发布:mac连接小米鼠标方法 编辑:程序博客网 时间:2024/05/14 11:33
点击打开链接

Kaka's Matrix Travels
Time Limit: 1000MS Memory Limit: 65536KTotal Submissions: 7062 Accepted: 2814

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 21 2 30 2 11 4 2

Sample Output

15

Source

POJ Monthly--2007.10.06, Huang, Jinsong

草图:

高兴,直接1A。

给你一个n*n的矩阵,每个格子都有一个非负整数,从左上角走到右下角,收集走过的数字,累加,但是只能向右或者向下走,走过之后数字就变为0,让你求从左上角到右下角,走k次之后,所得的最大值是多少。
最小费用最大流,但是题目要求的最大值,所以建图的时候需要加入的费用为负的。
将矩阵中的每个点视为网络中的节点,并且向它能够连接的点连接一条有向边,流量为inf,费用为0.对于点权存在,解决的方法就是拆点,然后两个点之间的容量为1,费用为点权,因为每走完一次之后,每个点权就变为0,所以下次走的时候可以将其当做跳板,所以拆的两个点之间还要连接一条边,容量为inf,费用为0.因为要走k次,所以建立一个超级源点与第一个点相连,流量为inf,费用为0,最后建立一个超级汇点与最后一个点相连,容量为inf,费用为0.最后的最后就是spfa模板。
#include<iostream>#include<algorithm>#include<cstring>#include<queue>#include<cstdio>using namespace std;const int MAXN=610*610*2+2;const int inf=1<<29;int pre[MAXN];          // pre[v] = k:在增广路上,到达点v的边的编号为kint dis[MAXN];          // dis[u] = d:从起点s到点u的路径长为dint vis[MAXN];         // inq[u]:点u是否在队列中int path[MAXN];int head[MAXN];int NE,tot,ans,max_flow,map[666][666];struct node{    int u,v,cap,cost,next;} Edge[MAXN<<2];void addEdge(int u,int v,int cap,int cost){    Edge[NE].u=u;    Edge[NE].v=v;    Edge[NE].cap=cap;    Edge[NE].cost=cost;    Edge[NE].next=head[u];    head[u]=NE++;    Edge[NE].v=u;    Edge[NE].u=v;    Edge[NE].cap=0;    Edge[NE].cost=-cost;    Edge[NE].next=head[v];    head[v]=NE++;}int SPFA(int s,int t)                   //  源点为0,汇点为sink。{    int i;    for(i=s;i<=t;i++) dis[i]=inf;    memset(vis,0,sizeof(vis));    memset(pre,-1,sizeof(pre));    dis[s] = 0;    queue<int>q;    q.push(s);    vis[s] =1; while(!q.empty())        //  这里最好用队列,有广搜的意思,堆栈像深搜。    {        int u =q.front();        q.pop();        for(i=head[u]; i!=-1;i=Edge[i].next)        {            int v=Edge[i].v;            if(Edge[i].cap >0&& dis[v]>dis[u]+Edge[i].cost)            {                dis[v] = dis[u] + Edge[i].cost;                pre[v] = u;                path[v]=i;                if(!vis[v])                {                    vis[v] =1;                    q.push(v);                }            }        }        vis[u] =0;    }    if(pre[t]==-1)        return 0;    return 1;}void end(int s,int t){    int u, sum = inf;    for(u=t; u!=s; u=pre[u])    {        sum = min(sum,Edge[path[u]].cap);    }    max_flow+=sum;                          //记录最大流    for(u = t; u != s; u=pre[u])    {        Edge[path[u]].cap -= sum;        Edge[path[u]^1].cap += sum;        ans += sum*Edge[path[u]].cost;     //  cost记录的为单位流量费用,必须得乘以流量。    }}int main(){    int i,j,n,s,t,k;    while(scanf("%d%d",&n,&k)!=EOF)    {        int nn=n*n;        memset(head,-1,sizeof(head));        NE=ans=max_flow=s=0;        for(int i=1;i<=n;i++)            for(int j=1;j<=n;j++)                scanf("%d",&map[i][j]);        for(int i=1;i<=n;i++)            for(int j=1;j<=n;j++)            {                int num=(i-1)*n+j;                addEdge(num,num+nn,1,-map[i][j]);                addEdge(num,num+nn,inf,0);                if(j!=n)                    addEdge(num+nn,num+1,inf,0);                if(i!=n)                    addEdge(num+nn,num+n,inf,0);            }        addEdge(s,1,k,0);        t=nn*2+1;        addEdge(nn*2,t,inf,0);        while(SPFA(s,t))        {            end(s,t);        }        printf("%d\n",-ans);    }    return 0;}



原创粉丝点击