您的位置:首页 > 其它

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

2018-01-11 17:56 399 查看
这道题其实不算难,是个经典的基础题目,题目并不是很容易理解

有n个商店,m个提供商,k种商品
接下来n行,每行有k个数字,表示这个商店需要各个物品的个数。
再接下来m行,对于每一个提供商也有k个数字,表示这个提供商拥有各个物品的个数。
然后,对于每个物品k,都有n行m列的矩阵。
i行j列表示:
从j提供商向i商店运送一个k商品的代价是多少。
判断所有的仓库能否满足所有客户的需求,如果可以,求出最少的运输总费用。

无非就是原来是一件物品,现在变为了K件物品了

那么可以一个循环,循环K次,然后每次只看一件物品

在建图的时候,用源点对供应商,流量为供应商的提供量。

供应商对商店,流量为无限

商店对汇点,流量为商店的需求量

cost就额外输入,只用记录该件物品从供应点 i 运送到商店 j 的代价,注意要反向弧也要记录

#include <iostream>
#include <queue>
#include <string.h>
#include <stdio.h>
using namespace std;
#define INF 0x3f3f3f3f;
#define MAXV 160
#define min(a,b) (a>b?b:a)

int n,m,k,source,sink,maxflow,mincost;
int res[MAXV][MAXV],cost[MAXV][MAXV],nn[MAXV][MAXV],mm[MAXV][MAXV];
int parent[MAXV],d[MAXV];

void spfa()
{
queue <int>q;
int i,v;
bool vis[MAXV];
memset(parent,-1,sizeof(parent));
memset(vis,false,sizeof(vis));

for(i=source; i<=sink; i++) d[i]=INF;
d[source]=0;
q.push(source);
vis[source]=true;

while(!q.empty())
{
v=q.front();
q.pop();
vis[v]=false;

for(i=0; i<=sink; i++)
{
if(res[v][i] && d[v]+cost[v][i]<d[i])
{
d[i]=d[v]+cost[v][i];
parent[i]=v;
if(!vis[i])
{
vis[i]=true;
q.push(i);
}
}
}
}
}

void MCMF()
{
int v,minflow;
maxflow=0;
while(1)
{
spfa();                 //走一次最短路
if(parent[sink]==-1) break;//如果最短路没有

minflow=INF;            //找出最短路径的最小增广流
v=sink;
while(parent[v]!=-1)
{
minflow=min(minflow,res[parent[v]][v]);//将最短路的路径搜索一遍,找出最小流
v=parent[v];
}

v=sink;                 //对增广路进行流增广
while(parent[v]!=-1)
{
res[parent[v]][v]-=minflow;
res[v][parent[v]]+=minflow;
v=parent[v];
}
maxflow+=minflow;
mincost+=d[sink]*minflow;           //总的代价
}
}

void build_gragh(int x)
{
int i,j;
memset(res,0,sizeof(res));

for(i=1; i<=n; i++) res[i][sink]=nn[i][x];       //商店指向汇点
for(i=1; i<=m; i++) res[source][i+n]=mm[i][x];   //源点指向提供商

for(i=1; i<=m; i++)                              //提供商对商店的流量为无限大
{
for(j=1; j<=n; j++)
res[i+n][j]=INF;
}
}

int main()
{
int i,j,r,flag;
int need[MAXV],have[MAXV];
while(scanf("%d%d%d",&n,&m,&k) && n || m || k)
{
memset(need,0,sizeof(need));
memset(have,0,sizeof(have));
source=0,sink=n+m+1,mincost=0;

for(i=1; i<=n; i++)
{
for(j=1; j<=k; j++)
{
scanf("%d",&nn[i][j]);//nn暂时储存第i个商店K种物品的数量
need[j]+=nn[i][j];//need储存k种物品需要的总量
}
}

for(i=1; i<=m; i++)
{
for(j=1; j<=k; j++)
{
scanf("%d",&mm[i][j]);//mm储存每个进货点K种物品的数量
have[j]+=mm[i][j];//have储存k种物品可以提供的总量
}
}

flag=0;
for(i=1; i<=k; i++)
{
if(need[i]>have[i])          //如果某种物品的需求大于提供商能够提供的物品就输出-1
{
flag=1;
break;
}
}

for(r=1; r<=k; r++)              //K种物品一种一种来
{
memset(cost,0,sizeof(cost));

for(i=1; i<=n; i++)
{
for(j=1; j<=m; j++)
{
scanf("%d",&cost[j+n][i]);
cost[i][j+n]=-cost[j+n][i];         //反向路径要设为负权值
}
}
if(flag) continue;              //如果中途有一种物品不符合情况,那么可以直接break
build_gragh(r);                 //建图
MCMF();                         //费用流
if(need[r]>maxflow) flag=1;    //比较最大流与这种物品所需要的总和
}

if(flag) printf("-1\n");
else printf("%d\n",mincost);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息