XVI Open Cup named after E.V. Pankratiev. GP of Ekaterinburg--I.Iron man

泄露秘密 提交于 2020-04-08 09:08:26

n个服务器,k类任务,每个服务器完成一个任务都有特定的花费$cost_{i,j}$,但是你设置好某台机器去完成某项任务时他只能去完成这类任务,除非你可以花费$C$去更改配置。第$i$天要求去完成$q_{i,j}$个j类任务,问如何让总代价最小

用费用流去优化dp

#include <bits/stdc++.h>
using namespace std;
#define rep(i, j, k) for (int i = int(j); i <= int(k); ++ i)
#define dwn(i, j, k) for (int i = int(j); i >= int(k); -- i)
typedef long long LL;
typedef pair<int, int> P;
typedef vector<int> VI;
typedef vector<P> VII;
const int inf = 1e9;
const int N  = 50;
int cost[20][20], a[110][20], dp[110];
struct Edge {
    int from, to, cap, flow, cost;
};
struct MCMF {
    int n;
    vector<Edge> edges;
    vector<int> g[N];
    int inq[N], d[N], p[N], a[N];
    void add(int u, int v, int cap, int cost) {
        edges.push_back((Edge){u, v, cap, 0, cost});
        edges.push_back((Edge){v, u, 0, 0, -cost});
        int m = edges.size();
        g[u].push_back(m - 2);
        g[v].push_back(m - 1);
    }
    bool spfa(int s, int t, int &flow, int &cost){
        rep(i, 0, n) d[i] = inf;
        memset(inq, 0, sizeof(inq));
        d[s] = 0; inq[s] = 1; p[s] = 0; a[s] = inf;
        queue<int> Q;
        Q.push(s);
        while (!Q.empty()) {
            int u = Q.front(); Q.pop();
            inq[u] = 0;
            for (int i = 0; i < g[u].size(); ++ i) {
                Edge &e = edges[g[u][i]];
                if (e.cap > e.flow && d[e.to] > d[u] + e.cost) {
                    d[e.to] = d[u] + e.cost;
                    p[e.to] = g[u][i];
                    a[e.to] = min(a[u], e.cap - e.flow);
                    if (!inq[e.to]) {
                        Q.push(e.to);
                        inq[e.to] = 1;
                    }
                }
            }
        }
        if (d[t] == inf) return 0;
        flow += a[t];
        cost += d[t] * a[t];
        int u = t;
        while (u != s) {
            edges[p[u]].flow += a[t];
            edges[p[u] ^ 1].flow -= a[t];
            u = edges[p[u]].from;
        }
        return 1;
    }
    int minCost(int s, int t) {
        int flow = 0, cost = 0;
        while (spfa(s, t, flow, cost)) continue; return cost;
    }
}solver;

int main() {
    int n, k, c, m;
    scanf("%d%d%d", &n, &k, &c);   // n个服务器,k类任务
    scanf("%d", &m);
    memset(cost, -1, sizeof(cost));
    rep(i, 1, m) {
        int s, t, w;
        scanf("%d%d%d", &s, &t, &w);
        cost[s][t] = w; // s 完成第t个任务的代价为w
    }
    int q;
    scanf("%d", &q);
    rep(i, 1, q) {
        rep(j, 1, k) scanf("%d", &a[i][j]); // 第i天需要j服务器的数量
        rep(j, 1, k) a[i][j] = a[i - 1][j] + a[i][j];
    }
    auto calcCost = [&](int l, int r) -> int{
        static int sum[20];
        rep(i, 1, k) sum[i] = a[r][i] - a[l - 1][i];    
        // rep(i, 1, k) cout << sum[i] << ' '; cout << '\n';
        rep(i, 0, solver.n) solver.g[i].clear();
        solver.edges.clear();
        // n 个服务器, k 类任务
        int src = n + k + 1, dest = n + k + 2;
        solver.n = dest;
        rep(i, 1, n) solver.add(src, i, 1, 0);
        rep(i, 1, n) rep(j, 1, k) 
            if (cost[i][j] >= 0 && sum[j]) solver.add(i, j + n, 1, cost[i][j] * sum[j]);
        // 必须要第i个服务器可以完成第j类任务
        rep(i, 1, k) solver.add(i + n, dest, sum[i] > 0, 0);
        return solver.minCost(src, dest);
    };
    dp[0] = 0;
    rep(i, 1, q) {
        dp[i] = inf;
        rep(j, 0, i - 1) dp[i] = min(dp[i], dp[j] + calcCost(j + 1, i) + c);
    }
    printf("%d\n", dp[q]);
}
/*
5 5 10
12
1 1 63
2 1 37
2 2 12
3 2 98
5 2 57
2 3 74
3 3 55
4 3 32
1 4 62
3 4 18
2 5 21
4 5 42
10
97 20 29 95 46
51 32 96 53 37
60 85 50 23 94
92 11 53 26 46
66 64 18 0 58
18 2 3 97 37
17 11 73 7 93
36 30 31 27 51
22 35 31 77 1
83 68 66 64 64
*/

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!