最小费用流第一题,这个卡的……
最后认真膜拜了大神的博客 终于做出来了!!!
题目大意:
有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; }