第一次见到这样的题,真的是看别人的思想然后看别人的代码了一晚上,先明白别人的代码的意思,但是不懂为什么那么写,然后画个图忽然就明白了,下面就是根据这道题最初最小费用最大流的分析!
题目大意:给出n个客户对k个商品的需求量,又给出m个仓库对k个物品的存货量以及对k个物品从i仓库到j客户的一个物品的运费价格,让判断是否可以满足客户需求,然后就是如果满足求出最小的运费,是典型的最小费用最大流!
题目解析:可以将k中物品分开求最小然后想加!
建图,对每个仓库是一个结点,每个客户也是一个结点,除此之外再加上s源点和t结束点!
1、s到仓库i的边的权值为仓库i的供给量
2、仓库i到客户j的权值为仓库的供给量
3、客户j到t的权值为客户的需求量
4、还有建立花费图,cost[i][j]代表仓库i到客户j的没一个物品的运费
然后用spfa算法求s到t的最小路径(路径上边的权值不为0),如果到t的最短路径有更新(此条路径话费最少),则记录这条路径,求出这条路径上权值最小的边的权值,然后这条路径上所有的边的权值都减去该边的权值min,此时最小的花费增加了min*在这条边上的花费!如果s到t的值没有更新,则对于k物品的最小花费则已经求出来了!
表达能力不强,脑袋清楚说不出来,下面是代码,如果实在不明白的话就好好看看代码哈!
- #include<iostream>
- #include<cstdio>
- #include<string>
- #include<cmath>
- #include<queue>
- using namespace std;
- #define min(a,b) (a)<(b)?(a):(b)
- #define N 130
- #define inf 100000000
- int need[N][N];
- int offer[N][N];
- int map[N][N],cost[N][N];
- int sum_need[N],sum_offer[N];
- int n,m,K;
- int pre[N];
- int s,t;//源点和结束点
- int spfa()
- {
- int dis[N];
- bool vis[N];
- int i;
- queue<int>q;
- for(i=0; i<=t; i++)
- {
- vis[i]=false;
- dis[i]=inf;
- }
- vis[s]=true;
- dis[s]=0;
- q.push(s);
- while(!q.empty())
- {
- int k=q.front();
- vis[k]=false;
- q.pop();
- for(i=0; i<=t; i++)
- {
- if(map[k][i] && dis[i]>dis[k]+cost[k][i])
- {
- dis[i]=dis[k]+cost[k][i];
- pre[i]=k;
- if(vis[i]==false)
- {
- vis[i]=true;
- q.push(i);
- }
- }
- }
- }
- if(dis[t]!=inf)
- return 1;
- else
- return 0;
- }
- int fond()
- {
- int i,j;
- int Min=INT_MAX;
- j=0;
- while(spfa())
- {
- for(i=t;i!=s; i=pre[i])
- Min=min(Min,map[pre[i]][i]);
- for(i=t; i!=s; i=pre[i])
- {
- map[pre[i]][i]-=Min;
- map[i][pre[i]]+=Min;
- j+=cost[pre[i]][i]*Min;
- }
- }
- return j;
- }
- int main()
- {
- int i,j,k,sum,sign;
- while(scanf("%d%d%d",&n,&m,&K))
- {
- if(n==0 && m==0 && K==0)
- break;
- sum=0;
- memset(sum_need,0,sizeof(sum_need));
- memset(sum_offer,0,sizeof(sum_offer));
- for(i=1; i<=n; i++)
- for(j=1; j<=K; j++)
- {
- scanf("%d",&need[i][j]);
- sum_need[j]+=need[i][j];
- }
- for(i=1; i<=m; i++)
- for(j=1; j<=K; j++)
- {
- scanf("%d",&offer[i][j]);
- sum_offer[j]+=offer[i][j];
- }
- sign=0;
- for(i=1; i<=K; i++)
- if(sum_offer[i]<sum_need[i])
- {
- sign=1;
- break;
- }
- s=0;
- t=m+n+1;
- for(k=1; k<=K; k++)
- {
- for(i=0; i<=t; i++)
- for(j=0; j<=t; j++)
- map[i][j]=cost[i][j]=0;
- for(i=1+m; i<=n+m; i++)
- for(j=1; j<=m; j++)
- {
- scanf("%d",&cost[j][i]);
- cost[i][j]=-cost[j][i];
- }
- if(sign==1)
- continue;
- for(i=1; i<=m; i++)
- map[s][i]=offer[i][k];
- for(i=1; i<=m; i++)
- for(j=1+m; j<=n+m; j++)
- map[i][j]=offer[i][k];
- for(i=m+1; i<=m+n; i++)
- map[i][t]=need[i-m][k];
- sum+=fond();
- }
- if(sign==1)
- printf("-1\n");
- else
- printf("%d\n",sum);
- }
- return 0;
- }