标签:
Time Limit: 4000MS | Memory Limit: 65536K | |
Total Submissions: 14275 | Accepted: 4895 |
Description
Input
Output
Sample Input
1 3 3 1 1 1 0 1 1 1 2 2 1 0 1 1 2 3 1 1 1 2 1 1 1 1 1 3 2 20 0 0 0
Sample Output
4 -1
Source
大致题意:
有N个供应商,M个店主,K种物品。每个供应商对每种物品的的供应量已知,每个店主对每种物品的需求量的已知,从不同的供应商运送不同的货物到不同的店主手上需要不同的花费,又已知从供应商Mj送第kind种货物的单位数量到店主Ni手上所需的单位花费。
问:供应是否满足需求?如果满足,最小运费是多少?
解题思路:
费用流问题。
(1)输入格式
在说解题思路之前,首先说说输入格式,因为本题的输入格式和解题时所构造的图的方向不一致,必须要提及注意。以样例1为例:
(2)题目分析和拆解:
A、首先处理“供应是否满足需求”的问题。
要总供应满足总需求,就必须有 每种物品的供应总量都分别满足其需求总量,只要有其中一种物品不满足,则说明供不应求,本组数据无解,应该输出-1。但是要注意这里判断无解后,只能做一个标记,但还要继续输入,不然一旦中断输入,后面的几组数据结果就全错了。
而要知道“每种物品的供应总量都分别满足其需求总量”,对所有供应商第kind种物品的供应量求和ksupp[kind],对所有店主第kind种物品的需求量求和kneed[kind],然后比较ksupp[kind]与kneed[kind]就可以了。
而最小费用流的计算是建立在“供等于求”或“供过于求”的基础上的。
B、最小费用问题
要直接求出“把所有物品从所有供应商运送到所有店主的最小费用MinTotalCost”是不容易的。但是求出“把第kind种物品从所有供应商运送到所有店主的最小费用MinCost[kind]”却简单得多,这就转化为经典的多源多汇的费用流问题,而最后只需要把K种物品的最小费用求和 MinCost[kind],就能得到运送所有物品的最小费用MinTotalCost。
其实题目的输入方式最后要输入K个矩阵已经暗示了我们要拆解处理。
C、构图
那么对于第kind种物品如何构图呢?
解决多源多汇网络问题,必须先构造与其等价的单源单汇网络。构造超级源s和超级汇t,定义各点编号如下:
超级源s编号为0,供应商编号从1到M,店主编号从M+1到M+N,超级汇t编号为M+N+1。
令总结点数Nump=M+N+2,申请每条边的“花费”空间cost[Nump][ Nump]和“容量”空间cap[Nump][ Nump],并初始化为全0。
超级源s向所有供应商M建边,费用为0,容量为供应商j的供应量。
每个供应商都向每个店主建边,正向弧费用为输入数据的第kind个矩阵(注意方向不同),容量为供应商j的供应量;反向弧费用为正向弧费用的负数,容量为0。
所有店主向超级汇t建边,费用为0,容量为店主i的需求量。
注意:1、其他没有提及的边,费用和容量均为0,容量为0表示饱和边或不连通。
2、计算每种物品的最小费用都要重复上述工作重新构图,不过存储空间cost和cap不必释放,可重新赋值再次利用。
#include<map> #include<string> #include<cstring> #include<cstdio> #include<cstdlib> #include<cmath> #include<queue> #include<vector> #include<iostream> #include<algorithm> #include<bitset> #include<climits> #include<list> #include<iomanip> #include<stack> #include<set> using namespace std; int head[110],tail; struct Edge { int from,to,cap,flow,cost,next; }edge[10000000]; void add(int from,int to,int cap,int flow,int cost) { edge[tail].from=from; edge[tail].to=to; edge[tail].cap=cap; edge[tail].flow=flow; edge[tail].cost=cost; edge[tail].next=head[from]; head[from]=tail++; } int dis[110],p[110],re[110],ed; bool iq[110]; bool bf(int &flow,int &cost) { fill(dis,dis+ed+1,INT_MAX); memset(iq,0,sizeof(iq)); dis[0]=0; iq[0]=1; re[0]=INT_MAX; queue<int>qq; qq.push(0); while(qq.size()) { int from=qq.front(); qq.pop(); iq[from]=0; for(int i=head[from];i!=-1;i=edge[i].next) { Edge &e=edge[i]; if(e.cap>e.flow&&dis[e.to]>dis[from]+e.cost) { dis[e.to]=dis[from]+e.cost; p[e.to]=i; re[e.to]=min(re[from],e.cap-e.flow); if(!iq[e.to]) { qq.push(e.to); iq[e.to]=1; } } } } if(dis[ed]==INT_MAX) return 0; flow+=re[ed]; cost+=dis[ed]*re[ed]; int t=ed; while(t!=0) { edge[p[t]].flow+=re[ed]; edge[p[t]^1].flow-=re[ed]; t=edge[p[t]].from; } return 1; } int mincost(int goal) { int flow=0,cost=0; while(bf(flow,cost)); if(flow!=goal) return -1; return cost; } int a[60][60],b[60][60],c[60][60][60]; int main() { int n,m,k; while(scanf("%d%d%d",&n,&m,&k)!=EOF) { if(n==0&&m==0&&k==0) return 0; for(int i=1;i<=n;i++) for(int j=1;j<=k;j++) scanf("%d",&a[i][j]); for(int i=1;i<=m;i++) for(int j=1;j<=k;j++) scanf("%d",&b[i][j]); for(int i=1;i<=k;i++) for(int j=1;j<=n;j++) for(int ii=1;ii<=m;ii++) scanf("%d",&c[i][j][ii]); ed=n+m+1; int ans=0; for(int i=1;i<=k;i++) { tail=0; memset(head,-1,sizeof(head)); for(int ii=1;ii<=m;ii++) { add(0,ii,b[ii][i],0,0); add(ii,0,0,0,0); for(int jj=1;jj<=n;jj++) { add(ii,m+jj,b[ii][i],0,c[i][jj][ii]); add(m+jj,ii,0,0,-c[i][jj][ii]); } } int goal=0; for(int ii=1;ii<=n;ii++) { goal+=a[ii][i]; add(m+ii,ed,a[ii][i],0,0); add(ed,m+ii,0,0,0); } int t=mincost(goal); if(t==-1) { ans=-1; break; } ans+=t; } printf("%d\n",ans); } }
标签:
原文地址:http://blog.csdn.net/stl112514/article/details/44812483