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
有N个供应商,M个店主,K种物品。每个供应商对每种物品的的供应量已知,每个店主对每种物品的需求量的已知,从不同的供应商运送不同的货物到不同的店主手上需要不同的花费,又已知从供应商Mj送第kind种货物的单位数量到店主Ni手上所需的单位花费。
问:供应是否满足需求?如果满足,最小运费是多少?
用spfa求n次最大流
解决多源多汇网络问题,必须先构造与其等价的单源单汇网络。构造超级源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的需求量。
ACcode:注意:1、其他没有提及的边,费用和容量均为0,容量为0表示饱和边或不连通。
2、计算每种物品的最小费用都要重复上述工作重新构图,不过存储空间cost和cap不必释放,可重新赋值再次利用。
#pragma warning(disable:4786)//使命名长度不受限制 #pragma comment(linker, "/STACK:102400000,102400000")//手工开栈 #include <map> #include <set> #include <queue> #include <cmath> #include <stack> #include <cctype> #include <cstdio> #include <cstring> #include <stdlib.h> #include <iostream> #include <algorithm> #define rd(x) scanf("%d",&x) #define rd2(x,y) scanf("%d%d",&x,&y) #define rds(x) scanf("%s",x) #define rdc(x) scanf("%c",&x) #define ll long long int #define maxn 305 #define mod 1000000007 #define INF 0x3f3f3f3f //int 最大值 #define FOR(i,f_start,f_end) for(int i=f_start;i<=f_end;++i) #define MT(x,i) memset(x,i,sizeof(x)) #define PI acos(-1.0) #define E exp(1) using namespace std; struct Edge{ int u,w,v,len,next; }e[100*maxn]; int head[maxn],cnt,s,t; int pre[maxn],mc[maxn]; int need[maxn][maxn],offer[maxn][maxn],carriage[maxn][maxn][maxn]; int spfa(int s,int t){ int u,v; int dist[maxn],visit[maxn]; queue<int>q; MT(dist,0x3f); MT(visit,0); MT(pre,-1); MT(mc,0x3f); dist[s]=0; visit[s]=1; q.push(s); while(!q.empty()){ u=q.front(); q.pop(); visit[u]=0; for(int k=head[u];k;k=e[k].next){ v=e[k].v; if(e[k].len&&dist[v]>dist[u]+e[k].w){ dist[v]=dist[u]+e[k].w; pre[v]=k; mc[v]=min(mc[u],e[k].len); if(!visit[v]){ q.push(v); visit[v]=1; } } } } if(dist[t]<INF)return dist[t]; return -1; } void handle(int flow){ for(int i=t;pre[i]+1;i=e[pre[i]].u){ e[pre[i]].len-=flow; e[pre[i]^1].len+=flow; } } void add(int u,int v,int w,int len){ cnt++; e[cnt].u=u;e[cnt].v=v;e[cnt].w=w;e[cnt].len=len; e[cnt].next=head[u];head[u]=cnt; } void bulid(int n,int m,int p){ MT(head,0); cnt=1;s=0;t=n+m+1; FOR(i,1,m){ add(s,i,0,offer[p][i]); add(i,s,0,0); } FOR(i,1,n){ add(i+m,t,0,need[p][i]); add(t,i+m,0,0); } FOR(i,1,m){ FOR(j,1,n){ add(i,j+m,carriage[p][i][j],INF); add(j+m,i,-carriage[p][i][j],0); } } } int main(){ int ans,sum; int n,m,p; int sum_of_offer[maxn],sum_of_need[maxn],flag; while(cin>>n>>m>>p&&(n+m+p)){ ans=0;flag=1; MT(sum_of_need,0); MT(sum_of_offer,0); FOR(i,1,n)FOR(j,1,p){rd(need[j][i]);sum_of_need[j]+=need[j][i];} FOR(i,1,m)FOR(j,1,p){rd(offer[j][i]);sum_of_offer[j]+=offer[j][i];} FOR(i,1,p)FOR(j,1,n)FOR(k,1,m)rd(carriage[i][k][j]); FOR(i,1,p) if(sum_of_offer[i]<sum_of_need[i]){ flag=0; break; } if(!flag){ printf("-1\n"); continue; } FOR(i,1,p){ bulid(n,m,i); sum=0; int k; while(k=spfa(s,t),k+1){ sum+=mc[t]*k; handle(mc[t]); } ans+=sum; } printf("%d\n",ans); } return 0; } /* 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 */