題目鏈接
題意:
N個銷售店 標號爲1 - N,M個供貨店,1 - M,
然後如果其中一個店主訂購商品,應該安排那個供應商向店主提供多少商品
以減少費用
從不同的供應地點向不同的店主運輸不同種類的單件貨物的成本可能不同
已知:
每個供應地點K種存貨,N個店主的K種貨物的訂單
以及不同的供應地點到不同的店主運輸不同種類的貨物的成本
求如何安排貨物供應以最小化運輸總成本
輸入
3 個數 N M K
N 行 店主的訂單 每行包含K個整數 (0 <= K <= 3)
表示店主需要的商品數量
M行 給出供應地點的存儲,每行K個整數,表示存儲在該供應地點的貨物數量
然後是 K個整數矩陣
(每個都有大小爲 N * M), 第i行的整數範圍(0,100),
第i行的第j列表示成本將第 K 個貨物的一個單位從第j個供應地運到第 i 個店主
輸入3個0結束
輸出
滿足所有店主的所有需求,則在一行中打印一個整數,這是最低成本;
否則只輸出“-1”。
數據範圍:
時間:4 S
N M K < 50
思路:
1)第一眼看題,就感覺像圖,供應商是點,銷售商是點,
然後把每個點再拆成K個邊(因爲有K個物品)
2)建邊 源點->每個供應商 (流量爲供應的物品, 費用0)
每個銷售商->匯點 (流量是所銷售的所有物品, 費用0)
供應商每個點->給它自己提供的貨物連線 (流量爲每種貨物的數量,費用爲0)
銷售商銷售的貨物->銷售商 (流量爲每種物品需要的量,費用0)
供應商提供的貨物 ->每個銷售商需要的貨物都連線 (流量爲INF, 費用爲單價)
3)上面的操作太複雜而且,邊太多關建圖就TLE了
下面給出另一種思路
1)我們每種物品跑一次費用流(對每一種物品求最小花費),
這樣建圖的複雜度就下降了
2)建邊,源點->每個供應商的第K種物品 (流量爲供應的物品, 費用0)
每個銷售商的第K種物品->匯點 (流量是所銷售的所有物品, 費用0)
就把每種供應商的第K種物品(點) -> 每個銷售商的第K個物品
(流量INF,費用爲Cost )
3)+個物品供給不足判斷
4)輸入要讀完,不然 會WA
AC:
#include<iostream>
#include<cstring>
#include<math.h>
#include<algorithm>
#include<stdio.h>
#include<queue>
#include<vector>
#define Del(a, b) memset(a, b, sizeof(a));
using namespace std;
const int maxn = 505;
const int inf = 0x3f3f3f3f;
int N, M, K;
int path[maxn], dis[maxn], head[maxn], vis[maxn], cnt;
int Cost[maxn][maxn];
void init() {
cnt = 0;
memset(head, -1, sizeof(head));
}
struct ac{
int v, flow, cost, nex;
}edge[maxn << 8];
void addEdge(int u, int v, int flow, int cost) {
edge[cnt] = {v, flow, cost, head[u]};
head[u] = cnt++;
edge[cnt] = {u, 0, -cost, head[v]};
head[v] = cnt++;
}
int Spfa(int s, int t) {
memset(vis, 0, sizeof(vis));
memset(dis, inf, sizeof(dis));
memset(path, -1, sizeof(path));
queue<int> que;
que.push(s);
dis[s] = 0;
vis[s] = 1;
while(!que.empty()) {
int u = que.front();
que.pop();
vis[u] = 0;
for(int i = head[u]; i != -1; i = edge[i].nex){
int v = edge[i].v;
int flow = edge[i].flow;
int cost = edge[i].cost;
if (flow > 0 && dis[v] > dis[u] + cost) { // 按費用增廣
dis[v] = dis[u] + cost;
path[v] = i;
if(vis[v]) continue;
vis[v] = 1;
que.push(v);
}
}
}
return dis[t] != inf;
}
int MCMF(int s, int t, int &cost) {
int maxflow = 0;
while(Spfa(s, t)) {
int flow = inf;
for (int i = path[t]; i != -1; i = path[edge[i ^ 1].v]) {
flow = min(flow, edge[i].flow);
}
for (int i = path[t]; i != -1; i = path[edge[i^1].v]) {
edge[i].flow -= flow;
edge[i^1].flow += flow;
cost += flow * edge[i].cost;
}
maxflow += flow;
}
return maxflow;
}
int Sal[70][70];
int Sup[70][70];
int main() {
//freopen("in.txt", "r", stdin);
while (scanf("%d%d%d", &N, &M, &K) && N && M && K) {
memset(Sal, 0, sizeof(Sal));
memset(Sup, 0, sizeof(Sup));
for (int i = 1; i <= N; ++i) {
for(int k = 1; k <= K; ++k) {
scanf("%d", &Sal[i][k]);
Sal[0][k] += Sal[i][k];
}
}
for(int i = 1; i <= M; ++i) {
for(int k = 1; k <= K; ++k) {
scanf("%d", &Sup[i][k]);
Sup[0][k] += Sup[i][k];
}
}
bool flag = 1;
int Ans = 0;
for(int k = 1; k <= K; ++k) {
if (Sup[0][k] < Sal[0][k]) { //物品供給不足
flag = 0;
break;
}
}
for(int k = 1; k <= K; ++k) {
init();
//建立源點到供應商的點 (流量爲 當前物品的總數,費用0)
for(int i = 1; i <= M; ++i) addEdge(0, i, Sup[i][k], 0);
//建立銷售商到匯點的點 (流量爲當前物品的總數, 費用爲0)
for(int i = 1; i <= N; ++i) addEdge(i + M, M + N + 1, Sal[i][k], 0);
int cost;
//建立當前物品的數量 從 供應商j 到 銷售商i 的運輸費用(流量爲inf, 費用爲 cost)
for (int i = 1; i <= N; ++i) {
for (int j = 1; j <= M; ++j) {
scanf("%d", &cost);
addEdge(j, M + i, inf, cost);
}
}
if(flag){ //因爲數據必須要讀完,不然會WA,物品供給不足,就只讀數據,不再跑費用流
int MF = MCMF(0, M + N + 1, Ans);
}
}
if (flag) printf("%d\n", Ans);
else printf("-1\n");
}
return 0;
}