【BZOJ3691】游行 最小可相交路径覆盖转化

 

因为C是不断变化的而且C是和点权相关和边权无关 所以我们可以MCMF但是MCMF的时候不能与C相关

再分析问题 我们可以认为每条路径S->T只覆盖T这个终点 因为题目中说了如果Si != Ti 要多付出 C的代价

假设我们走过的路径形成了一个环则刚好 边数=点数 覆盖完了

如果走过的路径不是一个环 则还有起点没有覆盖 此时我们可以把它当作没有途径的城市 给他补偿 同样为C

所以我们把原图拆成左边出点 右边入点 传递闭包后建图

这样每次MCMF增广的代价是不递减的 并且每增广一次多覆盖一个点 所以我们把每次增广的代价放到一个数组里面

每次询问我们二分C在数组里的位置,在C之前的点我们利用路径覆盖 在C及C之后的点我们用C去补偿它

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define MAX 255
inline int read() {
        int x = 0;
        bool t = false;
        char ch = getchar();
        while ((ch < '0' || ch > '9') && ch != '-')
                ch = getchar();
        if (ch == '-')
                t = true, ch = getchar();
        while (ch <= '9' && ch >= '0')
                x = x * 10 + ch - 48, ch = getchar();
        return t ? -x : x;
}
int val[MAX], sum[MAX], tot;
namespace MCMF {
        const int MAXM = 1000000, MAXN = 1000;
        struct Line {
                int v, next, w, fy;
        } e[MAXM];
        int h[MAXN], cnt = 2;
        inline void Add(int u, int v, int w, int fy) {
                e[cnt] = (Line) {
                        v, h[u], w, fy
                };
                h[u] = cnt++;
                e[cnt] = (Line) {
                        u, h[v], 0, -fy
                };
                h[v] = cnt++;
        }
        int dis[MAXN], pe[MAXN], pv[MAXN], Cost, Flow;
        bool vis[MAXN];
        queue<int> Q;
        int S = 0, T = MAXN - 1;
        bool SPFA() {
                memset(dis, 63, sizeof(dis));
                dis[S] = 0;
                Q.push(S);
                vis[S] = true;
                while (!Q.empty()) {
                        int u = Q.front();
                        Q.pop();
                        for (int i = h[u]; i; i = e[i].next) {
                                int v = e[i].v;
                                if (!e[i].w)
                                        continue;
                                if (dis[u] + e[i].fy < dis[v]) {
                                        dis[v] = dis[u] + e[i].fy;
                                        pe[v] = i, pv[v] = u;
                                        if (!vis[v])
                                                vis[v] = true, Q.push(v);
                                }
                        }
                        vis[u] = false;
                }
                if (dis[T] >= 1e9)
                        return false;
                int flow = 1e9;
                for (int i = T; i != S; i = pv[i])
                        flow = min(flow, e[pe[i]].w);
                for (int i = T; i != S; i = pv[i])
                        e[pe[i]].w -= flow, e[pe[i] ^ 1].w += flow;
                Flow += flow;
                Cost += dis[T] * flow;
                val[++tot] = dis[T] * flow;
                sum[tot] = sum[tot - 1] + val[tot];
                return true;
        }
}
using namespace MCMF;
int n, m, q, g[MAX][MAX];
int main() {
        n = read();
        m = read();
        q = read();
        memset(g, 63, sizeof(g));
        for (int i = 1; i <= n; ++i)
                g[i][i] = 0;
        for (int i = 1, u, v; i <= m; ++i)
                u = read(), v = read(), g[u][v] = min(read(), g[u][v]);
        for (int k = 1; k <= n; ++k)
                for (int i = 1; i <= n; ++i)
                        for (int j = 1; j <= n; ++j)
                                g[i][j] = min(g[i][j], g[i][k] + g[k][j]);
        for (int i = 1; i <= n; ++i)
                for (int j = 1; j <= n; ++j)
                        if (i ^ j)
                                Add(i, j + n, 1, g[i][j]);
        for (int i = 1; i <= n; ++i)
                Add(S, i, 1, 0), Add(i + n, T, 1, 0);
        while (SPFA());
        while (q--) {
                int C = read(), l = 1, r = tot, ret = 0;
                while (l <= r) {
                        int mid = (l + r) >> 1;
                        if (val[mid] < C)
                                l = mid + 1, ret = mid;
                        else
                                r = mid - 1;
                }
                printf("%d\n", sum[ret] + (n - ret)*C);
        }
        return 0;
}

 

猜你喜欢

转载自www.cnblogs.com/Aragaki/p/11757216.html