zoukankan      html  css  js  c++  java
  • 2019HDU多校Path——最短路最小割

    题目

    给出一个 $n$ 个顶点 $m$ 条边的图,要求阻塞一些边,使得从 $1$ 到 $n$ 的最短路变长,求阻塞的边长度和的最小值,不必保证阻塞后可达。

    分析

    很显然,要阻塞的边肯定在最短路图上,先跑一遍单源最短路,求出最短路图。

    要使最短路变长,肯定要同时切断原有的所有最短路,又要是长度(相当于流量)和最小,很容易想到就是求最小割。

    简而言之,就是在最短路图上求最小割。

    两个模板拼起来就好了(难得抄这么长的能一遍AC)

    #include<bits/stdc++.h>
    using namespace std;
    
    typedef long long ll;
    const ll INF = 1ll << 60;
    const int INF2 = 0x3f3f3f3f;
    const int maxv = 10000+10;        //最大顶点数
    const int maxn = maxv;
    const int maxe = 10000+10;        //最大边数
    ll dis[maxv];
    int cnt[maxv];
    bool inq[maxv];                //记录是否在队中
    int head[maxv], id; //head2[maxv], cnt2;
    int n, m;
    
    struct Edge
    {
        int to, w, next;
    }edge[maxe];
    
    inline void init()
    {
        memset(head, -1, sizeof(head));
        id=0;
    }
    
    inline void addedge(int u, int v, int w, int id)
    {
        edge[id].to = v;
        edge[id].w = w;
        edge[id].next = head[u];
        head[u] = id;
    }
    
    bool SPFA(int s)
    {
        deque<int>q;
        memset(inq, false, sizeof(inq));
        memset(cnt, 0, sizeof(cnt));
        for (int i = 1; i <= n; i++)  dis[i] = INF;
        dis[s] = 0;
        inq[s] = true;
        q.push_back(s);
    
        while (!q.empty())
        {
            int u = q.front(); q.pop_front();
            inq[u] = false;
            for (int i = head[u]; i != -1; i = edge[i].next)
            {
                int v = edge[i].to, w = edge[i].w;
                if (dis[v] > dis[u] + w)
                {
                    dis[v] = dis[u] + w;
                    if (!inq[v])
                    {
                        inq[v] = true;
                        //SLF优化
                        q.push_back(v);
                        if (++cnt[v] > n)  return false;
                        if (dis[q.back()] < dis[q.front()])
                        {
                            int k = q.back();
                            q.pop_back();
                            q.push_front(k);
                        }
                    }
                }
            }
        }
        return true;
    }
    
    struct Edge2{
        int from, to, cap, flow;
        Edge2(int u, int v, int c, int f):from(u), to(v), cap(c), flow(f){}
    };
    struct EdmondsKarp{
        int n, m;
        vector<Edge2>edges;      //边数的两倍
        vector<int>G[maxn];     //邻接表,G[i][j]表示结点i的第j条边在e数组中的序号
        int a[maxn];            //当起点到i的可改进量
        int p[maxn];        //最短树上p的入弧编号
    
        void init(int n)
        {
            for(int i = 0;i <= n;i++)  G[i].clear();
            edges.clear();
        }
    
        void AddEdge(int from, int to, int cap)
        {
            edges.push_back(Edge2(from, to, cap, 0));
            edges.push_back(Edge2(to, from, 0, 0));
            m = edges.size();
            G[from].push_back(m-2);
            G[to].push_back(m-1);
        }
    
        ll Maxflow(int s, int t)
        {
            ll flow = 0;
            for(;;)
            {
                memset(a, 0, sizeof(a));
                queue<int>Q;
                Q.push(s);
                a[s] = INF2;
                while(!Q.empty())
                {
                    int x = Q.front(); Q.pop();
                    for(int i = 0;i < G[x].size();i++)
                    {
                        Edge2& e = edges[G[x][i]];
                        if(!a[e.to] && e.cap > e.flow)
                        {
                            p[e.to] = G[x][i];
                            a[e.to] = min(a[x], e.cap-e.flow);
                            Q.push(e.to);
                        }
                    }
                    if(a[t])  break;
                }
                if(!a[t])  break;
                for(int u = t; u != s;u=edges[p[u]].from)
                {
                    edges[p[u]].flow += a[t];
                    edges[p[u]^1].flow -= a[t];
                }
                flow += a[t];
            }
            return flow;
        }
    }ek;
    
    int main()
    {
        int T;
        scanf("%d", &T);
        while(T--)
        {
            init();
            scanf("%d%d", &n, &m);
            for(int i = 0;i < m;i++)
            {
                int u, v, w;
                scanf("%d%d%d", &u, &v, &w);
                addedge(u, v, w, id++);
            }
            SPFA(1);
            ek.init(n);
            for(int i = 1;i <= n;i++)
            {
                for(int j = head[i]; j != -1;j = edge[j].next)
                {
                    int v = edge[j].to, w = edge[j].w;
                    if(dis[v]-dis[i] == w)
                        ek.AddEdge(i, v, w);
                }
            }
            printf("%lld
    ", ek.Maxflow(1, n));
        }
        return 0;
    }

    参考链接:https://blog.csdn.net/lgz0921/article/details/96891132#comments

  • 相关阅读:
    根据经纬度获取距离
    获取本浏览器经纬度坐标
    仿造mongodb的存储方式存一些假数据
    ty修饰符 public private static
    ty 枚举类型
    限制字符串的选择
    typeScript类型别名
    ty 函数的讲解
    ty数组的讲解
    接口的讲解
  • 原文地址:https://www.cnblogs.com/lfri/p/11291110.html
Copyright © 2011-2022 走看看