zoukankan      html  css  js  c++  java
  • 【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
    ", sum[ret] + (n - ret)*C);
            }
            return 0;
    }

     

  • 相关阅读:
    WPF中调用资源字典的方法
    DataGridView控制单元格修改的输入规则
    将dataGridView数据转成DataTable
    窗体打开后设置某个控件为默认的焦点
    自定义控件属性英文类别
    VMWare虚拟机与主机建立共享文件夹
    与.Net大师Jeffrey Richter面对面交流——TUP对话大师系列活动回顾(多图配详细文字)
    一个编程小题目引发的思考(下)
    一个Quicksort究竟可以写到多么短
    我是如何设计并实现一门程序设计语言——一门函数式编程语言Lucida的诞生
  • 原文地址:https://www.cnblogs.com/Aragaki/p/11757216.html
Copyright © 2011-2022 走看看