POJ - 2516 Minimum Cost(最小费用最大流)
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(最小费用最大流)的更多相关文章
- POJ 2516 Minimum Cost [最小费用最大流]
题意略: 思路: 这题比较坑的地方是把每种货物单独建图分开算就ok了. #include<stdio.h> #include<queue> #define MAXN 500 # ...
- Poj 2516 Minimum Cost (最小花费最大流)
题目链接: Poj 2516 Minimum Cost 题目描述: 有n个商店,m个仓储,每个商店和仓库都有k种货物.嘛!现在n个商店要开始向m个仓库发出订单了,订单信息为当前商店对每种货物的需求 ...
- POJ2516:Minimum Cost(最小费用最大流)
Minimum Cost Time Limit: 4000MS Memory Limit: 65536K Total Submissions: 19088 Accepted: 6740 题目链 ...
- POJ2516 Minimum Cost —— 最小费用最大流
题目链接:https://vjudge.net/problem/POJ-2516 Minimum Cost Time Limit: 4000MS Memory Limit: 65536K Tota ...
- Minimum Cost(最小费用最大流)
Description Dearboy, a goods victualer, now comes to a big problem, and he needs your help. In his s ...
- POJ 2516 Minimum Cost (最小费用最大流)
POJ 2516 Minimum Cost 链接:http://poj.org/problem?id=2516 题意:有M个仓库.N个商人.K种物品.先输入N,M.K.然后输入N行K个数,每一行代表一 ...
- POJ 2516 Minimum Cost (网络流,最小费用流)
POJ 2516 Minimum Cost (网络流,最小费用流) Description Dearboy, a goods victualer, now comes to a big problem ...
- POJ 2516 Minimum Cost(最小费用流)
Description Dearboy, a goods victualer, now comes to a big problem, and he needs your help. In his s ...
- POJ 2516 Minimum Cost
每个物品分开做最小费用最大流. #include<cstdio> #include<cstring> #include<cmath> #include<vec ...
随机推荐
- Python+selenium鼠标、键盘事件
鼠标操作 现在的Web产品提供了丰富的鼠标交互方式,例如鼠标右击.双击.悬停.甚至是鼠标拖动等功能,在Webdriver中,将这些关于鼠标操作的方法封装在ActionChains类提供. 1.鼠标右击 ...
- java常见问题集锦
Eclipse 编译错误 Access restriction:The type *** is not accessible due to restriction on... 解决方案 Eclipse ...
- 两行代码快速创建一个iOS主流UI框架
本框架适用于 使用 NavigationController+UITabBarController 的APP 框架QLSNavTab , GitHub地址:https://github.com/qia ...
- [NOIP1998] 提高组 洛谷P1011 车站
题目描述 火车从始发站(称为第1站)开出,在始发站上车的人数为a,然后到达第2站,在第2站有人上.下车,但上.下车的人数相同,因此在第2站开出时(即在到达第3站之前)车上的人数保持为a人.从第3站起( ...
- [USACO08OPEN]牛的车Cow Cars
题目描述 N (1 <= N <= 50,000) cows conveniently numbered 1..N are driving in separate cars along a ...
- Codeforces827D. Best Edge Weight
$n \leq 2e5,m \leq 2e5$的有边权图,对每条边问:不改其他边的情况下这条边最多能是多少使得他一定在所有最小生成树上,如果无穷大输出-1. 典型题+耗时题,CF上的绝望时刻..打VP ...
- POJ3150:Cellular Automaton
题意看不懂加题目想不通,很菜. n<=500个数围城环,每次操作对每个数Ai把与i在环上相距不超过d<n/2(包括Ai)的数加起来取模m<=1e6,求K<=1e7次操作后的环. ...
- 关闭spring整合kafka时,消费者一直打印kafka日志
在log4j.properties中添加如下代码 log4j.logger.org.apache.kafka.common.metrics.Metrics=OFF log4j.logger.org.a ...
- MySQL Slow Log慢日志分析【转】
如果你的MySQL出现了性能问题,第一个需要“诊断”的就是slow log(慢日志)了. slow log文件很小,使用more less等命令就足够了.如果slow log很大怎么办?这里介绍MyS ...
- mysql 修改管理员密码
mysql 修改管理员密码 本次学习环境: windows 7系统.mysql 5.7.14. 一.如果是忘记了用户密码: (1).关闭正在运行的MySQL服务. 方法一:可以直接操作wamp软件,左 ...