poj 2516(最小费用最大流)

来源:互联网 发布:windows phone 10升级 编辑:程序博客网 时间:2024/05/22 00:30
Minimum Cost
Time Limit: 4000MS Memory Limit: 65536KTotal Submissions: 16048 Accepted: 5625

Description

Dearboy, a goods victualer, now comes to a big problem, and he needs your help. In his sale area there are N shopkeepers (marked from 1 to N) which stocks goods from him.Dearboy has M supply places (marked from 1 to M), each provides K different kinds of goods (marked from 1 to K). Once shopkeepers order goods, Dearboy should arrange which supply place provide how much amount of goods to shopkeepers to cut down the total cost of transport.

It's known that the cost to transport one unit goods for different kinds from different supply places to different shopkeepers may be different. Given each supply places' storage of K kinds of goods, N shopkeepers' order of K kinds of goods and the cost to transport goods for different kinds from different supply places to different shopkeepers, you should tell how to arrange the goods supply to minimize the total cost of transport.

Input

The input consists of multiple test cases. The first line of each test case contains three integers N, M, K (0 < N, M, K < 50), which are described above. The next N lines give the shopkeepers' orders, with each line containing K integers (there integers are belong to [0, 3]), which represents the amount of goods each shopkeeper needs. The next M lines give the supply places' storage, with each line containing K integers (there integers are also belong to [0, 3]), which represents the amount of goods stored in that supply place.

Then come K integer matrices (each with the size N * M), the integer (this integer is belong to (0, 100)) at the i-th row, j-th column in the k-th matrix represents the cost to transport one unit of k-th goods from the j-th supply place to the i-th shopkeeper.

The input is terminated with three "0"s. This test case should not be processed.

Output

For each test case, if Dearboy can satisfy all the needs of all the shopkeepers, print in one line an integer, which is the minimum cost; otherwise just output "-1".

Sample Input

1 3 3   1 1 10 1 11 2 21 0 11 2 31 1 12 1 11 1 132200 0 0

Sample Output

4-1


题意:
有m个供应商n个客户k种产品,每个供应商到每个客户供应每种产品需要不同的花费。

求出最小花费下,满足所有顾客需求的最小费用。


思路:

这是最小费用最大流的模板题,难点主要是有k种产品,如果放在一起算的话会超时,因此要把k种产品分开算,每次求出最小花费。求最大流之前先求出k种商品的总需求和总供应量,如果不能满足需求直接输出-1.


#include<stdio.h>#include<iostream>#include<algorithm>#include<cstdio>#include<string.h>#include<vector>#include<queue>#include<stack>#include<list>#include<set>#include<math.h>#include<map>using namespace std;int n,m,k;  const int N=55;  const int M=1005;  const int MAX=1e9+7;  int pre[M];//存储前驱顶点  int dist[M];//存储到源点s的距离  int sumhave[N],sumneed[N];int inq[M];//每个顶点是否在队列中的标志  int min_c_f;//记录增广路径中的残留容量  int vertex;//顶点数  int sum;//保存最小费用    struct element  {      int c;//容量      int f;//流      int c_f;//残留容量      int v;//价值  } G[M][M];    int capn[N][N],capm[N][N],road[N][N][N];void init(int p)  {  sum=0;    vertex=n+m+1;//加入超源点0和超汇点,注意要+1,即抽象成网络流的结构      for(int u=0; u<=vertex; u++)//初始流为0,所以不用重构W(f);      {          for(int v=0; v<=vertex; v++)          {              G[u][v].c=G[v][u].c=0;              G[u][v].c_f=G[v][u].c_f=0;              G[u][v].f=G[v][u].f=0;              G[u][v].v=G[v][u].v=MAX;          }      }    //for(int p=0;p<k;p++)    for(int i=0; i<m; i++)      {          G[0][i+1].v=0;//从超源点到各个供应商之间的权值取为0          G[0][i+1].c=G[0][i+1].c_f=capm[i][p];//从超源点到各个供应商之间的容量          for(int j=0; j<n; j++)          {              int w=road[p][j][i];//计算供应商到每一个客户之间的价格            G[i+1][m+j+1].v=w;//将距离赋给对应的权值,注意第二个下标G[i+1][m+j+1].c=capn[j][p];//容量取为1              G[i+1][m+j+1].c_f=G[i+1][m+j+1].c;              G[m+j+1][vertex].v=0;//将从各个客户到超汇点之间的权值取为0            G[m+j+1][vertex].c=G[m+j+1][vertex].c_f=capn[j][p];//将从各个客户到超汇点之间的容量取为需求量        }      }  }    void SPFA(int s)//求最短路径的SPFA算法  {      queue<int> Q;      int u;      for(int i=0; i<=vertex; i++)//初始化      {          dist[i]=MAX;          pre[i]=-1;          inq[i]=0;      }      dist[s]=0;      Q.push(s);      inq[s] = 1;      while(!Q.empty())      {          u=Q.front();          Q.pop();          inq[u]=0;          for(int i=0; i<=vertex; i++)//更新u的邻接点的dist[], pre[], inq[]          {              int v=i;              if(G[u][v].c_f==0)     // 表示(u,v)没有边                  continue;              if(G[u][v].v==MAX)                  G[u][v].v=-G[v][u].v;              if(dist[v]>dist[u]+G[u][v].v)//松弛操作              {                  dist[v]=dist[u]+G[u][v].v;                  pre[v]=u;                  if(inq[v]==0)                  {                      Q.push(v);                      inq[v]=1;                  }              }          }      }  }    void ford_fulkerson(int s,int t)  {      SPFA(s);      while(pre[t]!=-1)//pre为-1表示没有找到从s到t的增广路径      {min_c_f=MAX;          int u=pre[t],v=t;//计算增广路径上的残留容量          while(u!=-1)          {              if(min_c_f > G[u][v].c_f)                  min_c_f=G[u][v].c_f;              v=u;              u=pre[v];          }  sum+=dist[t]*min_c_f;//将这一条最短路径的值加进sum,注意加上的花费是单位花费乘上流量          u=pre[t], v=t;          while(u!=-1)          {              G[u][v].f+=min_c_f; //修改流              G[v][u].f=-G[u][v].f;              G[u][v].c_f=G[u][v].c-G[u][v].f; //修改残留容量              G[v][u].c_f=G[v][u].c-G[v][u].f;              v=u;              u=pre[v];          }        SPFA(s);      }  }    int main()  {      //freopen("in.txt","r",stdin);      while(scanf("%d%d%d",&n,&m,&k)!=EOF)      {  if(n==0&&m==0&&k==0)break; memset(sumhave,0,sizeof(sumhave));memset(sumneed,0,sizeof(sumneed));for(int i=0;i<n;i++)for(int j=0;j<k;j++){scanf("%d",&capn[i][j]);sumneed[j]+=capn[i][j];}for(int i=0;i<m;i++)for(int j=0;j<k;j++){scanf("%d",&capm[i][j]);sumhave[j]+=capm[i][j];} for(int i=0;i<k;i++)for(int j=0;j<n;j++)for(int p=0;p<m;p++)scanf("%d",&road[i][j][p]);int flag=0;for(int i=0;i<k;i++){if(sumneed[i]>sumhave[i]){flag=1;break;}}if(flag==1){printf("-1\n");continue;}int ans=0;for(int i=0;i<k;i++)        {init(i);ford_fulkerson(0,vertex);//计算从超源点0到超汇点vertex之间的最小费用最大流  ans+=sum;}printf("%d\n",ans);    }      return 0;  }  


0 0
原创粉丝点击