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种商品
接下来 n*k的矩阵,表示每个商店需要每个商品的数目;
再接下来m*k矩阵,表示每个提供商拥有每个商品的个数。
然后,对于每个物品k,都有n*m的矩阵。
i行j列表示:
从j提供商向i商店运送一个k商品的代价是多少。
判断所有的仓库能否满足所有客户的需求,如果可以,求出最少的运输总费用。
思路:关键是建图,建立一个源点是s = 0 和 汇点 t = n+m+1;
源点到m个供应商,费用为0,容量是这个提供商能够提供这种物品的数量;
每个供应商到每个商店,费用为输入的费用(添加双向边),容量为无穷大;
每个商店到汇点,费用为0,容量为这个商店需要这种商品的数目。
还要考虑到供不应求的情况,当需求量大于供应量时,不能满足,输出-1.
对于第r种商品,若它的需求量大于最大流量,也不能满足,输出-1;
对每1个商品进行建图寻找增光路,最后累加输出最小费用就行了;
1 #include<stdio.h> 2 #include<string.h> 3 #include<queue> 4 #include<algorithm> 5 using namespace std; 6 7 const int maxn = 200; 8 const int INF = 0x3f3f3f3f; 9 int n,m,k; 10 int nn[maxn][maxn],need[maxn]; 11 int hh[maxn][maxn],have[maxn]; 12 int cost[maxn][maxn],res[maxn][maxn];//cost[i][j]表示i到j的费用,res[i][j]表示i到j的当前容量 13 int s, t; 14 int mincost,maxflow; 15 int dis[maxn],pre[maxn]; 16 void build_graph(int x) 17 { 18 memset(res,0,sizeof(res)); 19 for(int i = 1; i <= m; i++) 20 res[s][i+n] = hh[i][x];//源点指向每个供应商,费用为0,容量为该供应商提供的第r种商品 21 for(int i = 1; i <= n; i++) 22 res[i][t] = nn[i][x];//所有商店指向汇点,费用为0,容量为该供应商需要的第r种商品 23 for(int i = 1; i <= m; i++) 24 { 25 for(int j = 1; j <= n; j++) 26 res[i+n][j] = INF;//每个供应商指向每个商店,容量为无穷大。 27 } 28 } 29 void spfa() 30 { 31 queue<int>que; 32 while(!que.empty()) 33 que.pop(); 34 memset(pre,-1,sizeof(pre)); 35 int inque[maxn]; 36 memset(inque,0,sizeof(inque)); 37 for(int i = s; i <= t; i++) 38 dis[i] = INF; 39 dis[s] = 0; 40 inque[s] = 1; 41 que.push(s); 42 43 while(!que.empty()) 44 { 45 int u = que.front(); 46 que.pop(); 47 inque[u] = 0; 48 49 for(int i = 0; i <= n+m+1; i++) 50 { 51 if(res[u][i] && dis[i] > dis[u] + cost[u][i]) 52 { 53 dis[i] = dis[u] + cost[u][i]; 54 pre[i] = u; 55 if(!inque[i]) 56 { 57 inque[i] = 1; 58 que.push(i); 59 } 60 } 61 } 62 } 63 } 64 65 void MCMF() 66 { 67 maxflow = 0;//增光第r种商品的总流量,初始化为0; 68 int minflow;//当前增光路上可增加的最小流量; 69 while(1) 70 { 71 spfa(); 72 if(pre[t] == -1)//找不到增光路,退出 73 break; 74 75 minflow = INF; 76 for(int u = t; u != s; u = pre[u]) 77 { 78 minflow = min(minflow,res[ pre[u] ][u]);//寻找该增光路上的最小流量 79 } 80 for(int u = t; u != s; u = pre[u]) 81 { 82 res[ pre[u] ][u] -= minflow; 83 res[u][ pre[u] ] += minflow; 84 } 85 maxflow += minflow; 86 mincost += minflow*dis[t]; 87 } 88 } 89 90 int main() 91 { 92 while(~scanf("%d %d %d",&n,&m,&k)) 93 { 94 if(n == 0 && m == 0 && k == 0) 95 break; 96 bool flag = 0; 97 s = 0;//源点 98 t = n+m+1;//汇点 99 mincost = 0;//最小费用初始化; 100 memset(need,0,sizeof(need)); 101 memset(have,0,sizeof(have)); 102 //nn[i][j]表示第i个商店需求nn[i][j]个第j种商品; 103 for(int i = 1; i <= n; i++) 104 { 105 for(int j = 1; j <= k; j++) 106 { 107 scanf("%d",&nn[i][j]); 108 need[j] += nn[i][j]; 109 } 110 } 111 //hh[i][j]表示第i个供应商拥有hh[i][j]个第j中商品; 112 for(int i = 1; i <= m; i++) 113 { 114 for(int j = 1; j <= k; j++) 115 { 116 scanf("%d",&hh[i][j]); 117 have[j] += hh[i][j]; 118 } 119 } 120 //如果第i种商品的需求量大于供应量,标记为1,但后面的仍然要继续输入 121 for(int i = 1; i <= k; i++) 122 { 123 if(need[i] > have[i]) 124 { 125 flag = 1; 126 break; 127 } 128 } 129 //下面输入k个n*m的矩阵,其第i行第j列表示第j个供应商向第i个商店运送第k个商品的单位费用; 130 for(int r = 1; r <= k; r++) 131 { 132 memset(cost,0,sizeof(cost)); 133 for(int i = 1; i <= n; i++) 134 { 135 for(int j = 1; j <= m; j++) 136 { 137 scanf("%d",&cost[j+n][i]); 138 cost[i][j+n] = -cost[j+n][i];//注意添加双向边 139 } 140 } 141 if(flag) continue;//如果已经不合法,就不用建图,但数据要继续输入 142 143 build_graph(r); 144 MCMF(); 145 if(need[r] > maxflow) flag = 1;//如果第r种商品的需求量大于最大流量,也不合法。 146 } 147 if(flag) printf("-1\n"); 148 else printf("%d\n",mincost); 149 } 150 return 0; 151 }