• POJ3422Kaka's Matrix Travels(最小费用最大流)


    题意:有个方阵,每个格子里都有一个非负数,从左上角走到右下角,每次走一步,只能往右或往下走,经过的数字拿走,换0

    每次都找可以拿到数字和最大的路径走,走k次,求最大和

    分析:最大费用最大流。因为点有权值,所以一般的做法是拆点,将一个点拆成两个点a和a',点的费用为权值,容量为1,然后再建一条边,边的费用为0,容量为INF,这样就能保证至少能通过这个点k次。。然后将a‘与右或下的点建一条边,边的费用为0,容量为INF..最后建一个超级源点和汇点,使之只能走k编。将超级源点与矩阵第一个点相连,费用为0,容量为k,超级汇点与矩阵最后一个点相连,费用为0,容量为k。这样,这个题的图就建完了。。

    一开始手贱把if(j<n)打成if(j>n)了。。又调试了半天。。最大流题目不能手贱啊,手贱就跪了。。!!!

    // File Name: 3422.cpp
    // author: zlbing
    // created time: 2013/3/3 22:17:43
    #include<iostream>
    #include<string>
    #include<algorithm>
    #include<cstdlib>
    #include<cstdio>
    #include<set>
    #include<map>
    #include<vector>
    #include<cstring>
    #include<stack>
    #include<cmath>
    #include<queue>
    using namespace std;
    #define CL(x,v); memset(x,v,sizeof(x));
    #define INF 0x3f3f3f3f
    #define LL long long
    #define MAXN 50*50*2+10
    #define REP(i,n) for(int i=0;i<n;i++)
    #define REP1(i,n) for(int i=1;i<n+1;i++)
    struct Edge{
        int from,to,cap,flow,cost;
    };
    struct MCMF{
        int n,m,s,t;
        vector<Edge>edges;
        vector<int> G[MAXN];
        int inq[MAXN];
        int d[MAXN];
        int p[MAXN];
        int a[MAXN];
        void init(int n){
            this->n=n;
            for(int i=0;i<=n;i++)G[i].clear();
            edges.clear();
        }
        void AddEdge(int from,int to,int cap,int cost){
            edges.push_back((Edge){from,to,cap,0,cost});
            edges.push_back((Edge){to,from,0,0,-cost});
            m=edges.size();
            G[from].push_back(m-2);
            G[to].push_back(m-1);
        }
        bool BellmanFord(int s,int t,int& flow,int& cost){
            for(int i=0;i<=n;i++)d[i]=INF;
                CL(inq,0);
            d[s]=0;inq[s]=1;p[s]=0;a[s]=INF;
    
            queue<int>Q;
            Q.push(s);
            while(!Q.empty()){
                int u=Q.front();Q.pop();
                inq[u]=0;
                for(int i=0;i<G[u].size();i++){
                    Edge& e=edges[G[u][i]];
                    if(e.cap>e.flow&&d[e.to]>d[u]+e.cost){
                        d[e.to]=d[u]+e.cost;
                        p[e.to]=G[u][i];
                        a[e.to]=min(a[u],e.cap-e.flow);
                        if(!inq[e.to]){
                            Q.push(e.to);
                            inq[e.to]=1;
                        }
                    }
                }
            }
            if(d[t]==INF)return false;
            flow+=a[t];
            cost+=d[t]*a[t];
            int u=t;
            while(u!=s){
                edges[p[u]].flow+=a[t];
                edges[p[u]^1].flow-=a[t];
                u=edges[p[u]].from;
            }
            return true;
        }
        int Mincost(int s,int t){
            int flow=0,cost=0;
            while(BellmanFord(s,t,flow,cost));
            return cost;
        }
    };
    MCMF solver;
    int main(){
        int n,k;
        while(~scanf("%d%d",&n,&k))
        {
            int s=0;
            int t=2*n*n+1;
            solver.init(t);
            REP1(i,n){
                REP1(j,n){
                    int tmp;
                    scanf("%d",&tmp);
                    solver.AddEdge(n*(i-1)+j,n*(i-1)+j+n*n,1,-tmp);
                    solver.AddEdge(n*(i-1)+j,n*(i-1)+j+n*n,k-1,0);
                    if(i<n)
                        solver.AddEdge(n*(i-1)+j+n*n,n*i+j,INF,0);
                    if(j<n)
                        solver.AddEdge(n*(i-1)+j+n*n,n*(i-1)+j+1,INF,0);
                }
            }
            solver.AddEdge(s,1,k,0);
            solver.AddEdge(n*n*2,t,k,0);
            int ans=0;
            ans=-solver.Mincost(s,t);
            printf("%d\n",ans);
        }
        return 0;
    }
  • 相关阅读:
    PHP观察者模式
    php减少损耗的方法之一 缓存对象
    php迭代器模式
    数据库安全措施的改进依据------未实践
    mysql利用phpmyadmin导入数据出现#1044错误 的可能原因
    两列布局的基本思路
    less1.5中的减错误
    ie63像素bug原因及解决办法不使用hack
    镜像翻转二叉树
    判断一个整数是否是 2 的幂次方
  • 原文地址:https://www.cnblogs.com/arbitrary/p/2943421.html
Copyright © 2020-2023  润新知