1、K种物品,M个供应商,N个收购商。每种物品从一个供应商运送到一个收购商有一个单位运费。每个收购商都需要K种物品中的若干。求满足所有收购商需求的前提下的最小运费。

2、K种物品拆开来,分别对每种物品进行最小费用最大流计算。

建立超级源点和超级汇点:超级源点流向M个供应商,容量为供应商的存储量,费用为0;N个收购商流向超级源点,容量为收购商的需求量,费用为0。

另外,供应商流向收购商,容量为无穷大,费用为对应的单位运费。

3、

1、Bellman-Ford:

#include<iostream>
#include<stdio.h>
#include<vector>
#include<string.h>
#include<queue>
using namespace std; const int maxn=;
const int INF=0x3f3f3f3f; struct Edge{
int from,to,cap,flow,cost;
Edge(int u,int v,int c,int f,int w):from(u),to(v),cap(c),flow(f),cost(w){}
}; struct MCMF{
int n,m;
vector<Edge>edges;
vector<int>G[maxn];
int inq[maxn];//是否在队列中
int d[maxn];//Bellman-Ford
int p[maxn];//上一条弧
int a[maxn];//可改进量 void init(int n){
this->n=n;
for(int i=;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,,cost));
edges.push_back(Edge(to,from,,,-cost));
m=edges.size();
G[from].push_back(m-);
G[to].push_back(m-);
} bool BellmanFord(int s,int t,int &flow,long long &cost){
for(int i=;i<n;i++)d[i]=INF;
memset(inq,,sizeof(inq));
d[s]=;inq[s]=;p[s]=;a[s]=INF; queue<int>Q;
Q.push(s);
while(!Q.empty()){
int u=Q.front();Q.pop();
inq[u]=;
for(int i=;i<(int)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]=;}
}
}
}
if(d[t]==INF)return false;
flow+=a[t];
cost+=(long long)d[t]*(long long)a[t];
for(int u=t;u!=s;u=edges[p[u]].from){
edges[p[u]].flow+=a[t];
edges[p[u]^].flow-=a[t];
}
return true;
} //需要保证初始网络中没有负权圈
int MincostMaxflow(int s,int t,long long &cost){
int flow=;cost=;
while(BellmanFord(s,t,flow,cost));
return flow;
}
}MM; int main(){
int N,M,K;//汇点个数,源点个数,物品种类
int need[][];//need[i][j]表示第i个店主需要第j种商品的数量
int totalneed[];//totalneed[i]表示第i种商品的总需求量
int storage[][];//storage[i][j]表示第i个仓库里存储的第j种商品的数量
int totalstorage[];//totalstorage[i]表示第i种商品的总存储量
int cost[][];//cost[i][j]表示当前这个商品从第j个仓库运送到第i个店主的单位价格
bool flag;//false表示存储量不足
long long mincost;//最小花费
int maxflow;//最大流
long long totalcost;
int totalflow;
int S,T;//超级源点,超级汇点 while(~scanf("%d%d%d",&N,&M,&K)){
if(N==&&M==&&K==)break;
memset(totalneed,,sizeof(totalneed));
memset(totalstorage,,sizeof(totalstorage));
flag=true;
totalcost=;
totalflow=; for(int i=;i<N;++i){
for(int j=;j<K;++j){
scanf("%d",&need[i][j]);
totalneed[j]+=need[i][j];
}
}
for(int i=;i<M;++i){
for(int j=;j<K;++j){
scanf("%d",&storage[i][j]);
totalstorage[j]+=storage[i][j];
}
}
for(int i=;i<K;++i){
if(totalneed[i]>totalstorage[i]){
flag=false;
break;
}
} for(int k=;k<K;++k){
MM.init(N+M+);//初始化要放这里
for(int i=;i<N;++i){
for(int j=;j<M;++j){
scanf("%d",&cost[i][j]);
MM.AddEdge(j,M+i,INF,cost[i][j]);//注意加边:j->M+i
}
}
if(flag==false)continue; //超级源点
S=N+M;
for(int v=;v<M;++v){
MM.AddEdge(S,v,storage[v][k],);
}
//超级汇点
T=N+M+;
for(int v=;v<N;++v){
MM.AddEdge(M+v,T,need[v][k],);
} maxflow=MM.MincostMaxflow(S,T,mincost);
if(maxflow<totalneed[k])
flag=false; totalcost+=mincost;
totalflow+=maxflow;
} if(flag==false)printf("-1\n");
else printf("%lld\n",totalcost);
}
return ;
}

2、SPFA版费用流:

/*
SPFA版费用流
最小费用最大流,求最大费用最大流只需要取相反数,结果取相反数即可。
点的总数为N,点的编号0~N-1
*/
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<queue>
using namespace std; const int MAXN=;
const int MAXM=;
const int INF=0x3f3f3f3f;
struct Edge{
int to,next,cap,flow,cost;
}edge[MAXM];
int head[MAXN],tol;
int pre[MAXN],dis[MAXN];
bool vis[MAXN];
int N;//节点总个数,节点编号从0~N-1
void init(int n){
N=n;
tol=;
memset(head,-,sizeof(head));
}
void addedge(int u,int v,int cap,int cost){
edge[tol].to=v;
edge[tol].cap=cap;
edge[tol].cost=cost;
edge[tol].flow=;
edge[tol].next=head[u];
head[u]=tol++;
edge[tol].to=u;
edge[tol].cap=;
edge[tol].cost=-cost;
edge[tol].flow=;
edge[tol].next=head[v];
head[v]=tol++;
}
bool spfa(int s,int t){
queue<int>q;
for(int i=;i<N;i++){
dis[i]=INF;
vis[i]=false;
pre[i]=-;
}
dis[s]=;
vis[s]=true;
q.push(s);
while(!q.empty()){
int u=q.front();
q.pop();
vis[u]=false;
for(int i=head[u];i!=-;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);
}
}
}
}
if(pre[t]==-)return false;
else return true;
}
//返回的是最大流,cost存的是最小费用
int minCostMaxflow(int s,int t,int &cost){
int flow=;
cost=;
while(spfa(s,t)){
int Min=INF;
for(int i=pre[t];i!=-;i=pre[edge[i^].to]){
if(Min>edge[i].cap-edge[i].flow)
Min=edge[i].cap-edge[i].flow;
}
for(int i=pre[t];i!=-;i=pre[edge[i^].to]){
edge[i].flow+=Min;
edge[i^].flow-=Min;
cost+=edge[i].cost*Min;
}
flow+=Min;
}
return flow;
} int main(){
int N,M,K;//汇点个数,源点个数,物品种类
int need[][];//need[i][j]表示第i个店主需要第j种商品的数量
int totalneed[];//totalneed[i]表示第i种商品的总需求量
int storage[][];//storage[i][j]表示第i个仓库里存储的第j种商品的数量
int totalstorage[];//totalstorage[i]表示第i种商品的总存储量
int cost[][];//cost[i][j]表示当前这个商品从第j个仓库运送到第i个店主的单位价格
bool flag;//false表示存储量不足
int mincost;//最小花费
int maxflow;//最大流
int totalcost;
int totalflow;
int S,T;//超级源点,超级汇点 while(~scanf("%d%d%d",&N,&M,&K)){
if(N==&&M==&&K==)break;
memset(totalneed,,sizeof(totalneed));
memset(totalstorage,,sizeof(totalstorage));
flag=true;
totalcost=;
totalflow=; for(int i=;i<N;++i){
for(int j=;j<K;++j){
scanf("%d",&need[i][j]);
totalneed[j]+=need[i][j];
}
}
for(int i=;i<M;++i){
for(int j=;j<K;++j){
scanf("%d",&storage[i][j]);
totalstorage[j]+=storage[i][j];
}
}
for(int i=;i<K;++i){
if(totalneed[i]>totalstorage[i]){
flag=false;
break;
}
} for(int k=;k<K;++k){
init(N+M+);//初始化要放这里
for(int i=;i<N;++i){
for(int j=;j<M;++j){
scanf("%d",&cost[i][j]);
addedge(j,M+i,INF,cost[i][j]);//注意加边:j->M+i
}
}
if(flag==false)continue; //超级源点
S=N+M;
for(int v=;v<M;++v){
addedge(S,v,storage[v][k],);
}
//超级汇点
T=N+M+;
for(int v=;v<N;++v){
addedge(M+v,T,need[v][k],);
} maxflow=minCostMaxflow(S,T,mincost);
if(maxflow<totalneed[k])
flag=false; totalcost+=mincost;
totalflow+=maxflow;
} if(flag==false)printf("-1\n");
else printf("%d\n",totalcost);
}
return ;
}

3、zkw费用流:

/*
zkw费用流
对于二分图类型的比较高效
*/
#include<iostream>
#include<stdio.h>
#include<string.h>
using namespace std; const int MAXN=;
const int MAXM=;
const int INF=0x3f3f3f3f;
struct Edge{
int to,next,cap,flow,cost;
Edge(int _to=,int _next=,int _cap=,int _flow=,int _cost=):
to(_to),next(_next),cap(_cap),flow(_flow),cost(_cost){}
}edge[MAXM];
struct ZKW_MinCostMaxFlow{
int head[MAXN],tot;
int cur[MAXN];
int dis[MAXN];
bool vis[MAXN];
int ss,tt,N;//源点、汇点和点的总个数(编号是0~N-1),不需要额外赋值,调用会直接赋值
int min_cost,max_flow;
void init(){
tot=;
memset(head,-,sizeof(head));
}
void addedge(int u,int v,int cap,int cost){
edge[tot]=Edge(v,head[u],cap,,cost);
head[u]=tot++;
edge[tot]=Edge(u,head[v],,,-cost);
head[v]=tot++;
}
int aug(int u,int flow){
if(u==tt)return flow;
vis[u]=true;
for(int i=cur[u];i!=-;i=edge[i].next){
int v=edge[i].to;
if(edge[i].cap>edge[i].flow&&!vis[v]&&dis[u]==dis[v]+edge[i].cost){
int tmp=aug(v,min(flow,edge[i].cap-edge[i].flow));
edge[i].flow+=tmp;
edge[i^].flow-=tmp;
cur[u]=i;
if(tmp)return tmp;
}
}
return ;
}
bool modify_label(){
int d=INF;
for(int u=;u<N;u++)
if(vis[u])
for(int i=head[u];i!=-;i=edge[i].next){
int v=edge[i].to;
if(edge[i].cap>edge[i].flow&&!vis[v])
d=min(d,dis[v]+edge[i].cost-dis[u]);
}
if(d==INF)return false;
for(int i=;i<N;i++)
if(vis[i]){
vis[i]=false;
dis[i]+=d;
}
return true;
}
/*
直接调用获取最小费用和最大流
输入:start-源点,end-汇点,n-点的总个数(编号从0开始)
返回值:pair<int,int>第一个是最小费用,第二个是最大流
*/
pair<int,int> mincostmaxflow(int start,int end,int n){
ss=start,tt=end,N=n;
min_cost=max_flow=;
for(int i=;i<n;i++)dis[i]=;
while(){
for(int i=;i<n;i++)cur[i]=head[i];
while(){
for(int i=;i<n;i++)vis[i]=false;
int tmp=aug(ss,INF);
if(tmp==)break;
max_flow+=tmp;
min_cost+=tmp*dis[ss];
}
if(!modify_label())break;
}
return make_pair(min_cost,max_flow);
}
}solve; int main(){
int N,M,K;//汇点个数,源点个数,物品种类
int need[][];//need[i][j]表示第i个店主需要第j种商品的数量
int totalneed[];//totalneed[i]表示第i种商品的总需求量
int storage[][];//storage[i][j]表示第i个仓库里存储的第j种商品的数量
int totalstorage[];//totalstorage[i]表示第i种商品的总存储量
int cost[][];//cost[i][j]表示当前这个商品从第j个仓库运送到第i个店主的单位价格
bool flag;//false表示存储量不足
//int mincost;//最小花费
//int maxflow;//最大流
pair<int,int>pr; int totalcost;
int totalflow;
int S,T;//超级源点,超级汇点 while(~scanf("%d%d%d",&N,&M,&K)){
if(N==&&M==&&K==)break;
memset(totalneed,,sizeof(totalneed));
memset(totalstorage,,sizeof(totalstorage));
flag=true;
totalcost=;
totalflow=; for(int i=;i<N;++i){
for(int j=;j<K;++j){
scanf("%d",&need[i][j]);
totalneed[j]+=need[i][j];
}
}
for(int i=;i<M;++i){
for(int j=;j<K;++j){
scanf("%d",&storage[i][j]);
totalstorage[j]+=storage[i][j];
}
}
for(int i=;i<K;++i){
if(totalneed[i]>totalstorage[i]){
flag=false;
break;
}
} for(int k=;k<K;++k){
solve.init();//初始化要放这里
for(int i=;i<N;++i){
for(int j=;j<M;++j){
scanf("%d",&cost[i][j]);
solve.addedge(j,M+i,INF,cost[i][j]);//注意加边:j->M+i
}
}
if(flag==false)continue; //超级源点
S=N+M;
for(int v=;v<M;++v){
solve.addedge(S,v,storage[v][k],);
}
//超级汇点
T=N+M+;
for(int v=;v<N;++v){
solve.addedge(M+v,T,need[v][k],);
} pr=solve.mincostmaxflow(S,T,N+M+);
if(pr.first<totalneed[k])
flag=false; totalcost+=pr.first;
totalflow+=pr.second;
} if(flag==false)printf("-1\n");
else printf("%d\n",totalcost);
}
return ;
}

POJ - 2516 Minimum Cost(最小费用最大流)的更多相关文章

  1. POJ 2516 Minimum Cost [最小费用最大流]

    题意略: 思路: 这题比较坑的地方是把每种货物单独建图分开算就ok了. #include<stdio.h> #include<queue> #define MAXN 500 # ...

  2. Poj 2516 Minimum Cost (最小花费最大流)

    题目链接: Poj  2516  Minimum Cost 题目描述: 有n个商店,m个仓储,每个商店和仓库都有k种货物.嘛!现在n个商店要开始向m个仓库发出订单了,订单信息为当前商店对每种货物的需求 ...

  3. POJ2516:Minimum Cost(最小费用最大流)

    Minimum Cost Time Limit: 4000MS   Memory Limit: 65536K Total Submissions: 19088   Accepted: 6740 题目链 ...

  4. POJ2516 Minimum Cost —— 最小费用最大流

    题目链接:https://vjudge.net/problem/POJ-2516 Minimum Cost Time Limit: 4000MS   Memory Limit: 65536K Tota ...

  5. Minimum Cost(最小费用最大流)

    Description Dearboy, a goods victualer, now comes to a big problem, and he needs your help. In his s ...

  6. POJ 2516 Minimum Cost (最小费用最大流)

    POJ 2516 Minimum Cost 链接:http://poj.org/problem?id=2516 题意:有M个仓库.N个商人.K种物品.先输入N,M.K.然后输入N行K个数,每一行代表一 ...

  7. POJ 2516 Minimum Cost (网络流,最小费用流)

    POJ 2516 Minimum Cost (网络流,最小费用流) Description Dearboy, a goods victualer, now comes to a big problem ...

  8. POJ 2516 Minimum Cost(最小费用流)

    Description Dearboy, a goods victualer, now comes to a big problem, and he needs your help. In his s ...

  9. POJ 2516 Minimum Cost

    每个物品分开做最小费用最大流. #include<cstdio> #include<cstring> #include<cmath> #include<vec ...

随机推荐

  1. python的cache修饰器

    简单的memory cache.可以用来内存缓存任意函数方法. #!/usr/bin/python import functools from threading import RLock impor ...

  2. 一个监控oracle数据库某个字段值变化并发送邮件报警的脚本

    talk is cheap,here is the code: #!/bin/sh export ORACLE_HOME=/u01/app/oracle/product//client_1/ expo ...

  3. 75. Spring Boot 定制URL匹配规则【从零开始学Spring Boot】

    在之前有一篇文章说了,博客名称从原来的<从零开始学Spring Boot>更改为<Spring Boot常见异常汇总>,后来写了几篇文章之后发展,有些文章还是一些知识点,所以后 ...

  4. iOS-runtime-根据类名推送到任意控制器,且实现属性传值

    // // WJRuntime.m // RuntimeSkip // // Created by tqh on 15/9/8. // Copyright (c) 2015年 tqh. All rig ...

  5. [bzoj4006][JLOI2015]管道连接_斯坦纳树_状压dp

    管道连接 bzoj-4006 JLOI-2015 题目大意:给定一张$n$个节点$m$条边的带边权无向图.并且给定$p$个重要节点,每个重要节点都有一个颜色.求一个边权和最小的边集使得颜色相同的重要节 ...

  6. Substrings--poj1226(字符串)

    Description You are given a number of case-sensitive strings of alphabetic characters, find the larg ...

  7. 2017CodeM初赛B场

    A.合并字符串价值(loj6174) 分析: 普通暴力:枚举两个分界线,那么ans=Σmin(Al(c)+Bl(c),Ar(c)+Br(c)),这样是O(n^2),会TLE 考虑枚举a的分界线,b的答 ...

  8. java . 请在小于99999的正整数中找符合下列条件的数,它既是完全平方数,又有两位数字相同,如:144,676。

    import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; //请在小于99999的正整数中找符合下列条件的 ...

  9. ModelAndView对象作用

    ModelAndView ModelAndView对象有两个作用: 作用一  :设置转向地址,如下所示(这也是ModelAndView和ModelMap的主要区别) ModelAndView mv = ...

  10. 基于unicorn-engine的虚拟机的实现(WxSpectre)

    反病毒虚拟机是一个很有优势的工具,可以说反病毒软件是否存在模拟器是衡量反病毒软件能力的一个指标.反病毒虚拟机不光是内嵌在反病毒软件内部,来动态执行样本.这种虚拟机一般也可以单独用来动态执行批量样本,检 ...