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

来源:互联网 发布:java ftp删除文件 编辑:程序博客网 时间:2024/05/11 13:05
大致题意:
给出N和K,表示一个N*N个区域组成的的方阵map,方阵的每个区域都有自己的一个值map[i][j]。现从(0,0)点走到(n,n)点走K次,规定只能向右走或者向下走,每经过一个区域取走区域中的值,map[i][j]变为0,一个区域可以被多次经过。求最多能取走多少值。

大致思路:
    最小费用最大流。说实话一直觉得这道题算法叫最大费用最大流更合适,因为这里求的是取走费用总和的最大值。但是终归还是要用费用流的模版,毕竟只是最小费用流模版改了几个小地方而已。
    建图方案。因为这里并不规定一个区域最多走多少次,但是能获得其上面数字map[i][j]的次数只有一次,所以这里可以将一个点拆作两个点再用两条边连接他们。一条的流量是1费用是map[i][j],代表能得到收入map[i][j]的次数只有一次。另一条流量是inf费用是0,代表这个点可以被0收入地经过无数次。再将其拆出的第二个点与其下方和右方的点连上一条边,流量为inf费用为0。设一个超级原点0连接1,这条边流量是K,费用是0。然后对构造出的图从0到第2*N*N个点使用最小费用最大流模版。
    说到模版,本来想带poj 2135的模版来用,没想到tle了,最后看大牛的博客说在用spfa时使用堆栈会超时,换队列的spfa模版过了。哪位大牛知道这是为何的话麻烦帮忙给我解释解释啊。

详细代码:
#include<cstdio>#include<cstring>#include<iostream>using namespace std;const int inf=99999999;const int nMax=5005;struct{    int v, cap, cost, next, re;}edge[40005];int n,m,ans;int k,edgeHead[nMax];int que[5005],pre[5005],dis[5005];bool vis[5005];void addEdge(int u,int v,int ca,int co){    edge[k].v=v;    edge[k].cap=ca;    edge[k].cost=co;    edge[k].next=edgeHead[u];    edge[k].re=k + 1;    edgeHead[u]=k ++;    edge[k].v=u;    edge[k].cap=0;    edge[k].cost=-co;    edge[k].next=edgeHead[v];    edge[k].re=k - 1;    edgeHead[v]=k ++;}bool spfa(){    int i, head = 0, tail = 1;    //  长注释的地方就是从最小费用改到最大费用时需要变动的地方    for(i = 0; i <= n; i ++){        dis[i] = -1;////////////        vis[i] = false;    }    dis[0] = 0;    que[0] = 0;    vis[0] = true;    while(head != tail){        int u = que[head];        for(i = edgeHead[u]; i != 0; i = edge[i].next){            int v = edge[i].v;            if(edge[i].cap && dis[v] <dis[u] + edge[i].cost){////////                dis[v] = dis[u] + edge[i].cost;                pre[v] = i;                if(!vis[v]){                    vis[v] = true;                    que[tail ++] = v;                    if(tail == 5005) tail = 0;                }            }        }        vis[u] = false;        head++;        if(head ==5005) head = 0;    }    if(dis[n] ==-1) return false;///////////    return true;}void end(){    int u, p;    for(u = n; u != 0; u = edge[edge[p].re].v){        p = pre[u];        edge[p].cap -= 1;        edge[edge[p].re].cap += 1;        ans += edge[p].cost;    }}int main(){    int map[60][60];    int a,b,c,d,i,j,N,K;    k=1;    memset(edgeHead,0,sizeof(edgeHead));    memset(vis,0,sizeof(vis));    scanf("%d%d",&N,&K);    for(i=1;i<=N;i++){        for(j=1;j<=N;j++){            scanf("%d",&map[i][j]);        }    }    addEdge(0,1,K,0);    for(i=1;i<=N;i++){        for(j=1;j<=N;j++){            a=(i-1)*N+j;            a=a*2-1;            b=a+1;            addEdge(a,b,1,map[i][j]);            addEdge(a,b,K,0);            if(i<N)addEdge(b,a+2*N,K,0);            if(j<N)addEdge(b,b+1,K,0);        }    }    n=2*N*N;    ans=0;    while(spfa())end();    cout<<ans<<endl;    return 0;}