zoukankan      html  css  js  c++  java
  • POJ 3422 Kaka's Matrix Travels(拆点+最大费用流)题解

    题意:小A从左上角走到右下角,每个格子都有一个价值,经过这个格子就把价值拿走,每次只能往下或往右走,问你走k次最多能拿多少价值的东西。

    思路:这里有一个限制条件就是经过之后要把东西拿走,也就是每一格的价值只能拿一次,这也能用拆点。我们把一个点拆成两个,建两条边,一条流量1费用-cost,另一条流量k-1,费用0,这样就完成了。

    代码:

    #include<cstdio>
    #include<vector>
    #include<stack>
    #include<queue>
    #include<cstring>
    #include<string>
    #include<cmath>
    #include<cstdlib>
    #include<algorithm>
    #define ll long long
    const int maxn = 20000+5;
    const int maxm = 100000+5;
    const int MOD = 1e7;
    const int INF = 0x3f3f3f3f;
    using namespace std;
    struct Edge{
        int to,next,cap,flow,cost;
    }edge[maxm];
    int head[maxn],tot;
    int pre[maxn],dis[maxn];
    bool vis[maxn];
    int N,M;
    void init(){
        N = maxn;
        tot = 0;
        memset(head,-1,sizeof(head));
    }
    void addEdge(int u,int v,int cap,int cost){
        edge[tot].to = v;
        edge[tot].cap = cap;    //容量
        edge[tot].flow = 0;
        edge[tot].cost = cost;
        edge[tot].next = head[u];
        head[u] = tot++;
    
        edge[tot].to = u;
        edge[tot].cap = 0;
        edge[tot].flow = 0;
        edge[tot].cost = -cost;
        edge[tot].next = head[v];
        head[v] = tot++;
    }
    bool spfa(int s,int t){
        queue<int> q;
        for(int i = 0;i < N;i++){
            dis[i] = INF;
            vis[i] = false;
            pre[i] = -1;
        }
        dis[s] = 0;
        vis[s] = true;
        q.push(s);
        while(!q.empty()){
            int u = q.front();
            q.pop();
            vis[u] = false;
            for(int i = head[u];i != -1;i = edge[i].next){
                int v = edge[i].to;
                if(edge[i].cap > edge[i].flow && dis[v] > dis[u] + edge[i].cost){
                    dis[v] = dis[u] + edge[i].cost;
                    pre[v] = i;
                    if(!vis[v]){
                        vis[v] = true;
                        q.push(v);
                    }
                }
            }
        }
        return pre[t] != -1;
    }
    
    int MCMF(int s,int t,int &cost){
        int flow = 0;
        cost = 0;
        while(spfa(s,t)){
            int MIN = INF;
            for(int i = pre[t];i != -1;i = pre[edge[i^1].to]){
                if(MIN > edge[i].cap - edge[i].flow){
                    MIN = edge[i].cap - edge[i].flow;
                }
            }
            for(int i = pre[t];i != -1; i = pre[edge[i^1]. to]){
                edge[i]. flow += MIN;
                edge[i^1]. flow -= MIN;
                cost += edge[i]. cost * MIN;
            }
            flow += MIN;
        }
        return flow;
    }
    int mp[55][55],n;
    int lp(int i,int j){ return n*(i - 1) + j; };
    int rp(int i,int j){ return n*n + n*(i - 1) + j; }
    int main(){
        int k;
        while(scanf("%d%d",&n,&k) != EOF){
            init();
            for(int i = 1;i <= n;i++){
                for(int j = 1;j <= n;j++){
                    scanf("%d",&mp[i][j]);
                    addEdge(lp(i,j),rp(i,j),1,-mp[i][j]);
                    addEdge(lp(i,j),rp(i,j),k - 1,0);
                    if(i < n)
                        addEdge(rp(i,j),lp(i + 1,j),k,0);
                    if(j < n)
                        addEdge(rp(i,j),lp(i,j + 1),k,0);
                }
            }
            addEdge(0,lp(1,1),k,0);
            addEdge(rp(n,n),rp(n,n) + 1,k,0);
            int cost;
            MCMF(0,rp(n,n) + 1,cost);
            printf("%d
    ",-cost);
        }
        return 0;
    }
    
    
  • 相关阅读:
    Python基础语法 第2节课(数据类型转换、运算符、字符串)
    python基础语法 第5节课 ( if 、 for )
    python基础语法 第4节课 (字典 元组 集合)
    Python基础语法 第3节课 (列表)
    A. Peter and Snow Blower 解析(思維、幾何)
    C. Dima and Salad 解析(思維、DP)
    D. Serval and Rooted Tree (樹狀DP)
    C2. Balanced Removals (Harder) (幾何、思維)
    B. Two Fairs 解析(思維、DFS、組合)
    D. Bash and a Tough Math Puzzle 解析(線段樹、數論)
  • 原文地址:https://www.cnblogs.com/KirinSB/p/9408746.html
Copyright © 2011-2022 走看看