最小费用流第一题,这个卡的……
最后认真膜拜了大神的博客 终于做出来了!!!
题目大意:
有N个店铺,M个供货商,K种商品。给出每个供货商的仓库里每种商品的数量、每种商品给每个店铺供货的费用,每个店铺需要的各种商品的数量,求最小费用。
输入一开始是N,M,K。
然后 N行 ,每行 K列 ,第I行第J个数代表 第I个店铺 需要第J种物品多少件。
然后 M行 ,每行 K列 , 第I行第J个数代表 第I个供货商 有第J种物品多少件。
然后是K个矩阵 ,每个N行M列,第I个矩阵的第J行第D列代表着第D个供货商给第J个店铺发第I种货物一件需要的花费。
(输入的地方比较坑爹,请大家注意)
下面是代码:
#include <stdio.h>
#include <string.h>
#include <queue>
using namespace std;
const int M=105,inf=1<<30;
int need[M][M],have[M][M],cost[M][M][M],n,m,k;
int c[M][M];//针对某种物品的最大容量
int f[M][M];//流量
int w[M][M];//费用
int dis[M];//最短路算法中的距离数组,记录原点到其他点的距离
int pre[M]; //最短路中的记录数组,记录最短路径
bool vis[M]; //最短路算法中的标记数组 标记是否被访问过
int min(int a,int b)
{
if(a>b)
{
a=b;
}
return a;
}
bool spfa() //最少的费用,最短路算法
{
int i,j;
for(i=0;i<=n+m+1;i++) //初始化
{
dis[i]=inf;
pre[i]=-1;
vis[i]=false;
}
dis[0]=0;
vis[0]=true;
queue <int > q;
q.push(0); //初始化完成
while(!q.empty())
{
int t=q.front();
q.pop();
vis[t]=false;
for(i=1;i<=n+m+1;i++)
{
if(c[t][i]>f[t][i]&&dis[i]>dis[t]+w[t][i]) //如果流量没有到最大且超级原点经过点t到i的费用比直接到i小
{
dis[i]=dis[t]+w[t][i]; //更新到i点的最小花费
pre[i]=t; //更新最短路径中点i的前驱为t
if(!vis[i]) //如果点i没在队列中
{
q.push(i); //将点i放入队列
vis[i]=true; //标记已在队列中
}
}
}
}
if(pre[n+m+1]==-1)//如果超级汇点没有在对短路中 (因为没有前驱)
{
return false;//返回寻找最短路失败
}
return true; //返回最短路寻找成功
}
void getMaxflow() //寻找增广路
{
while(spfa())//如果最最小费用增广路寻找成功
{
int maxflow=inf;//初始化为最大值
int p=n+m+1;
while(pre[p]!=-1) //遍历最小费用增广路
{
maxflow=min(maxflow,c[pre[p]][p]-f[pre[p]][p]);//寻找关键流量,及最短路上的最小流量
p=pre[p];
}
p=n+m+1; //再次初始化;
while(pre[p]!=-1) //再次遍历最小费用增广路
{
f[pre[p]][p]+=maxflow;
f[p][pre[p]]=-f[pre[p]][p]; //调整流量
p=pre[p];
}
}
}
int main()
{
int i,j,d,ans;
while(scanf("%d%d%d",&n,&m,&k),n||m||k)
{
ans=0;
bool flat=false;
for(i=1;i<=n;i++) //输入部分
{
for(j=1;j<=k;j++)
{
scanf("%d",&need[i][j]);
}
}
for(i=1;i<=m;i++)
{
for(j=1;j<=k;j++)
{
scanf("%d",&have[i][j]);
}
}
for(i=1;i<=k;i++)
{
for(j=1;j<=n;j++)
{
for(d=1;d<=m;d++)
{
scanf("%d",&cost[i][d][j]);
}
}
} //输入部分完成
for(i=1;i<=k;i++)//对于每一种货物来说
{
memset(c,0,sizeof(c));
memset(f,0,sizeof(f));
memset(w,0,sizeof(w));
for(j=1;j<=m;j++)
{
c[0][j]=have[j][i];//超级远点到每个仓库的流量应该是仓库的存货量
}
for(j=1;j<=n;j++)
{
c[m+j][m+n+1]=need[j][i];//每个商店到超级汇点的容量应该是这个商店的需求量
}
for(j=1;j<=m;j++)
{
for(d=1;d<=n;d++)
{
c[j][d+m]=have[j][i];//每个仓库到商店的容量应该是仓库的存货量
}
}
for(j=1;j<=m;j++)
{
for(d=1;d<=n;d++)
{
w[j][d+m]=cost[i][j][d]; //供货商到商店的花费
w[d+m][j]=-cost[i][j][d]; //花费的负值,用于回流时
}
}
getMaxflow();//对第i种商品寻找最小费用流
for(j=1;j<=n;j++) //对于每一个商店来说
{
if(c[j+m][n+m+1]!=f[j+m][n+m+1]) //如果供货量不等于需求量
{
flat=true;
break;
}
}
if(flat) //出现供货不足 跳出
{
break;
}
for(j=1;j<=m;j++)
{
for(d=1;d<=n;d++)
{
ans+=f[j][d+m]*w[j][d+m];//计算总费用
}
}
}
if(flat)//出现供货不足
{
printf("-1\n");
}
else
{
printf("%d\n",ans);
}
}
return 0;
}