/*
translation:
M台机器要生产n个糖果,遵循如下规则:
1.糖果i的生产区间在(si, ti),花费是k*(pi-si),pi是实际开始生产的时间
2.机器j从初始化到生产糖果i所需的时间Cij,花费是Dij
3.任意机器从生产糖果i到生产糖果j,需花费时间Eij,花费Fij
求生产完所有糖果所需的最小时间?
solution:
最小费用流
note:
* 从s到每个糖果连上一条容量1,费用0的边,每台机器到t连上容量1,费用0的边
将每个糖果再次拆点,拆出来的点到t都连上一条容量1,费用0的边
每台机器和对应能够生产的糖果连上边,费用根据时间来计算,见代码
糖果之间能够转移的也连上一条边,费用同样根据时间来计算。
# 原来的建图方法是这样:糖果拆点,每个糖果和拆出来的点之间都连上一条容量1,费用0的边(保证糖果只被生产一次)
糖果和s连接,机器和t连接,能够相互转移的糖果之间也连上边。然后求流量n的最小费用流即可。但是这样是错误的,
因为有可能流量小于n的情况下就可以生产完全部的糖果。所以最小的费用时的流量不一定是n。
*/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <queue>
#include <utility>
using namespace std;
const int maxn = 1000;
const int INF = 0x3f3f3f3f;
typedef pair<int,int> P;
struct Edge
{
int to, cap, cost, rev;
Edge(int to_, int cap_, int cost_, int rev_):to(to_),cap(cap_),cost(cost_),rev(rev_){}
};
int V, n, m, k;
int S[maxn], T[maxn], C[maxn][maxn], D[maxn][maxn];
int E[maxn][maxn], F[maxn][maxn];
vector<Edge> G[maxn];
int h[maxn], dist[maxn], prevv[maxn], preve[maxn];
void add_edge(int from, int to, int cap, int cost)
{
//printf("from %d to %d, cap = %d, cost = %d\n", from, to, cap, cost);
G[from].push_back(Edge(to, cap, cost, G[to].size()));
G[to].push_back(Edge(from, 0, -cost, G[from].size()-1));
}
int min_cost_flow(int s, int t, int f)
{
int res = 0;
memset(h, 0, sizeof(h));
while(f > 0) {
priority_queue<P, vector<P>, greater<P> > pq;
fill(dist, dist + V, INF);
dist[s] = 0;
pq.push(P(0, s));
while(!pq.empty()) {
P p = pq.top(); pq.pop();
int v = p.second;
if(dist[v] < p.first) continue;
for(int i = 0; i < G[v].size(); i++) {
Edge& e = G[v][i];
if(e.cap > 0 && dist[e.to] > dist[v] + e.cost + h[v] - h[e.to]) {
dist[e.to] = dist[v] + e.cost + h[v] - h[e.to];
prevv[e.to] = v;
preve[e.to] = i;
pq.push(P(dist[e.to], e.to));
}
}
}
if(dist[t] == INF) return -1;
for(int v = 0; v < V; v++) h[v] += dist[v];
int d = f;
for(int v = t; v != s; v = prevv[v])
d = min(d, G[prevv[v]][preve[v]].cap);
f -= d;
res += d * h[t];
for(int v = t; v != s; v = prevv[v]) {
Edge& e = G[prevv[v]][preve[v]];
e.cap -= d;
G[v][e.rev].cap += d;
}
}
return res;
}
int main()
{
//freopen("in.txt", "r", stdin);
while(~scanf("%d%d%d", &n, &m, &k)) { //m machines, n candies
if(n + m + k == 0) break;
for(int i = 0; i < maxn; i++) G[i].clear();
for(int i = 0; i < n; i++) scanf("%d%d", &S[i], &T[i]);
for(int i = 0; i < n; i++) {
for(int j = 0; j < m; j++) {
scanf("%d", &C[i][j]);
}
}
for(int i = 0; i < n; i++) {
for(int j = 0; j < m; j++) {
scanf("%d", &D[i][j]);
}
}
for(int i = 0; i < n; i++) {
for(int j = 0; j < n; j++) {
scanf("%d", &E[i][j]);
}
}
for(int i = 0; i < n; i++) {
for(int j = 0; j < n; j++) {
scanf("%d", &F[i][j]);
}
}
int s = 2 * n + m, t = s + 1;
for(int i = 0; i < n; i++) add_edge(s, i, 1, 0);
for(int i = 0; i < m; i++) add_edge(i + n, t, 1, 0);
for(int i = 0; i < n; i++) add_edge(i + n + m, t, 1, 0);
for(int i = 0; i < n; i++) {
for(int j = 0; j < m; j++) {
if(C[i][j] >= T[i]) continue;
if(C[i][j] > S[i])
add_edge(i, j + n, 1, k * (C[i][j] - S[i]) + D[i][j]);
else
add_edge(i, j + n, 1, D[i][j]);
}
}
for(int i = 0; i < n; i++) {
for(int j = 0; j < n; j++) if(i != j) {
if(T[i] + E[i][j] < T[j]) {
if(T[i] + E[i][j] > S[j])
add_edge(j, i + n + m, 1, k * (T[i] + E[i][j] - S[j]) + F[i][j]);
else
add_edge(j, i + n + m, 1, F[i][j]);
}
}
}
V = t + 1;
printf("%d\n", min_cost_flow(s, t, n));
}
return 0;
}
hdu4780(*最小费用流)
最新推荐文章于 2021-02-27 12:46:13 发布