POJ-2516(最小费用最大流+MCMF算法)

Minimum Cost

POJ-2516

  • 题意就是有n个商家,有m个供货商,然后有k种商品,题目求的是满足商家的最小花费供货方式。
  • 对于每个种类的商品k,建立一个超级源点和一个超级汇点。每个商家和源点连线,容量为需要的商品数,每个供货商和汇点连线,容量为可以提供的商品数。
  • 然后对于商家和供货商之间的连线就是,容量为INF,而费用就是题目提供的费用信息。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<string>
#include<vector>
#include<queue>
#include<cmath>
using namespace std;
const int N=220;
const int INF=0X3F3F3F3F;
int n,m,k;//n表示商家,m表示供应商(0-50),k表示种类(0-3)
int need[N][N];//需求
int provide[N][N];//供应
int volume[N];//表示第k个品的所有的提供数目
struct Edge {
    int from, to, cap, flow, cost;
};
struct MCMF {
    int n, m;
    vector<Edge> edges;
    vector<int> G[N];
    int d[N], inq[N], p[N], a[N];

    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 spfa(int s, int t, int &flow, int &cost) {
        //M(inq, 0); M(d, INF);
        memset(inq,0,sizeof(inq));
        memset(d,INF,sizeof(d));
        d[s] = 0; inq[s] = 1; p[s] = 0; a[s] = INF;
        queue<int> q;
        q.push(s);
        while (!q.empty()) {
            int x = q.front(); q.pop();
            inq[x] = 0;
            for (int i = 0; i < G[x].size(); ++i) {
                Edge &e = edges[G[x][i]];
                if (d[e.to] > d[x] + e.cost && e.cap > e.flow) {
                    d[e.to] = d[x] + e.cost;
                    p[e.to] = G[x][i];
                    a[e.to] = min(a[x], e.cap-e.flow);
                    if (inq[e.to]) continue;
                    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 (spfa(s, t, flow, cost));
        return cost;
    }

}solver;
int main(){
    while(cin>>n>>m>>k&&(n||m||k)){
        memset(volume,0,sizeof(volume));
        for(int i=1;i<=n;i++){
            for(int j=1;j<=k;j++){
                cin>>need[i][j];
            }
        }
        for(int i=1;i<=m;i++){
            for(int j=1;j<=k;j++){
                cin>>provide[i][j];
                volume[j]+=provide[i][j];
            }
        }
        bool flag=true;
        int cost=0;
        for(int s=1;s<=k;s++){
            int s1=0,t=n+m+1;
            solver.init(n+m+1);
            int volume1=0;
            for(int i=1;i<=n;i++){
                solver.AddEdge(s1,i,need[i][s],0);
                volume1+=need[i][s];
            }
            if(volume1>volume[s])
                flag=false;
            for(int i=1;i<=n;i++){
                for(int j=1;j<=m;j++){
                    int co;
                    cin>>co;
                    solver.AddEdge(i,n+j,INF,co);
                }
            }
            for(int i=1;i<=m;i++){
                solver.AddEdge(i+n,t,provide[i][s],0);
            }
            if(flag){
                cost+=solver.Mincost(s1,t);
            }
        }
        if(flag)
            cout<<cost<<endl;
        else
        {
            cout<<-1<<endl;
        }
    }
    return 0;
}

原文地址:https://www.cnblogs.com/GarrettWale/p/11438319.html

时间: 2024-10-04 23:00:03

POJ-2516(最小费用最大流+MCMF算法)的相关文章

poj 2516 最小费用最大流

Language: Default Minimum Cost Time Limit: 4000MS   Memory Limit: 65536K Total Submissions: 14334   Accepted: 4908 Description Dearboy, a goods victualer, now comes to a big problem, and he needs your help. In his sale area there are N shopkeepers (m

POJ-2195(最小费用最大流+MCMF算法)

Going Home POJ-2195 这题使用的是最小费用流的模板. 建模的时候我的方法出现错误,导致出现WA,根据网上的建图方法没错. 这里的建图方法是每次到相邻点的最大容量为INF,而花费为1,因为花费等于距离.但是需要增加一个源点和一个汇点,然后将每个人和源点相连,每个房子和汇点相连,容量都为1,费用都为0. #include<iostream> #include<algorithm> #include<cstring> #include<queue>

hdu 2516 最小费用最大流

原来这个代码超时 #include<stdio.h> #include<queue> #include<string.h> using namespace std; #define N 200 #define inf 0x3fffffff int cap[N][N]; int fee[N][N]; int s,t,sum,pre[N]; int spfa() { queue<int>q; int dis[N],visit[N],u,i; memset(pre

poj 2195 最小费用最大流模板

/*Source Code Problem: 2195 User: HEU_daoguang Memory: 1172K Time: 94MS Language: G++ Result: Accepted Source Code */ #include <iostream> #include <stdio.h> #include <queue> #include <math.h> #include <string.h> using namespa

poj 2135(最小费用最大流)

Farm Tour Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 14730   Accepted: 5614 Description When FJ's friends visit him on the farm, he likes to show them around. His farm comprises N (1 <= N <= 1000) fields numbered 1..N, the first of

POJ - 2195 最小费用最大流

题意:每个人到每个房子一一对应,费用为曼哈顿距离,求最小的费用 题解:单源点汇点最小费用最大流,每个人和房子对于建边 #include<map> #include<set> #include<cmath> #include<queue> #include<stack> #include<vector> #include<cstdio> #include<cassert> #include<iomanip&

POJ 2195 - Going Home - [最小费用最大流][MCMF模板]

题目链接:http://poj.org/problem?id=2195 Time Limit: 1000MS Memory Limit: 65536K Description On a grid map there are n little men and n houses. In each unit time, every little man can move one unit step, either horizontally, or vertically, to an adjacent

poj 2135 最小费用最大流初步

这个题的意思是农夫约翰要呆人参观他的农场, 刚开始从1开始走, 走到N后又返回1点, 两次不能走相同的路, 问农夫约翰走的最短的路是多少?? 我们可以用最小MCMF来解决这个问题, 对于图中的每一条边, 我们建立了两条流量为1, 费用为边权的边, 再增加一个源点和一个汇点, 源点指向1, 流量为2,费用为0, N指向汇点, 流量为2费用为0, 然后求出最小费用即可, 代码如下: #include <cstdio> #include <algorithm> #include <

POJ 3680 最小费用最大流

这题来源:<算法竞赛经典入门-训练指南>中的367页:区间k覆盖问题. 思路:这题建图比较机智,我刚开始想到能建的图也就是离散化后两个端点连边,流量为1,费用为负的权值(因为求的是最大费用最大流),然后再加上源点和汇点,也就如此而已:但是这样建图样例第二和第四个不正确,因为中间没有联系的没连边,然后k就没用了. 原来最重要的连边是i和i+1之间的连边,流量为k,费用为0:为什么要连这些边呢,刚开始我也没想明白,后面才知道,因为有的端点之间你要让它们产生联系并且受制与k次,那么就得把这些点都连边