• 2017乌鲁木齐网络赛 J题 Our Journey of Dalian Ends ( 最小费用最大流 )


    题目链接

    题意 : 给出一副图,大连是起点,终点是西安,要求你求出从起点到终点且经过中转点上海的最小花费是多少?

    分析 :

    最短路是最小费用最大流的一个特例,所以有些包含中转限制或者经过点次数有限制的最短路问题都可以考虑使用最小费用最大流来建图解决。

    首先对于每个点都只能经过一次这个限制,在网络流中是比较常见的一个限制,只要将所有的点由一拆二且两点间连容量为 1 且花费为 0 的边。

    这题的建图很巧妙,是将中转点作为汇点,提示到了这里不如停下来想想如何建图?

    然后抽象出一个超级源点,然后将起点和终点与超级源点连一条容量为 1 且 花费为 0 的边,最后将上海这个中转点作为超级汇点。

    最后跑出的最小费用最大流就是答案,当然最大流应当是要等于 2 的,如果没有解则说明 MaxFlow < 2。

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn = 1e4 + 10;
    const int  INF = 0x3f3f3f3f;
    struct st{ int from, to, w; }arr[10010];
    map<string, int> mp;
    int id;
    
    struct Edge
    {
        int from,to,cap,flow,cost;
        Edge(int u,int v,int ca,int f,int co):from(u),to(v),cap(ca),flow(f),cost(co){};
    };
    
    struct MCMF
    {
        int n,m,s,t;
        vector<Edge> edges;
        vector<int> G[maxn];
        int inq[maxn];//是否在队列中
        int d[maxn];//距离
        int p[maxn];//上一条弧
        int a[maxn];//可改进量
    
        void init(int n)//初始化
        {
            this->n=n;
            for(int i=0;i<=n;i++)
                G[i].clear();
            edges.clear();
        }
    
        void AddEdge(int from,int to,int cap,int cost)//加边
        {
            edges.push_back(Edge(from,to,cap,0,cost));
            edges.push_back(Edge(to,from,0,0,-cost));
            int m=edges.size();
            G[from].push_back(m-2);
            G[to].push_back(m-1);
        }
    
        bool SPFA(int s,int t,int &flow,int &cost)//寻找最小费用的增广路,使用引用同时修改原flow,cost
        {
            for(int i=0;i<n;i++)
                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]--;
                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])
                        {
                            inq[e.to]++;
                            Q.push(e.to);
                        }
                    }
                }
            }
            if(d[t]==INF) return false;//汇点不可达则退出
            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 true;
        }
    
        int MincotMaxflow(int s,int t)
        {
            int flow=0,cost=0;
            while(SPFA(s,t,flow,cost));
            return cost;
        }
    }MM;
    
    inline void init()
    {
        mp.clear();
        mp["Shanghai"] = 1;///中转点上海
        mp["Dalian"] = 2;///起点大连
        mp["Xian"] = 3;///终点西安
        id = 4;
    }
    
    int main(void)
    {
        int nCase;
        cin>>nCase;
        while(nCase--){
            init();
            int M;
            cin>>M;
            string From, To;
            int Weight;
            for(int i=1; i<=M; i++){
                cin>>From>>To>>Weight;
                if(!mp.count(From)) mp[From] = id++;
                if(!mp.count(To)) mp[To] = id++;
                arr[i].from = mp[From];
                arr[i].to = mp[To];
                arr[i].w = Weight;
            }
    
            int n = id-1;
            MM.init(2*n+1);
            MM.AddEdge(0, 2, 1, 0);
            MM.AddEdge(0, 3, 1, 0);
            for(int i=1; i<=n; i++)
                MM.AddEdge(i, i+n, 1, 0);
            for(int i=1; i<=M; i++){
                MM.AddEdge(arr[i].from+n, arr[i].to, 1, arr[i].w);
                MM.AddEdge(arr[i].to+n, arr[i].from, 1, arr[i].w);
            }
    
            printf("%d
    ", MM.MincotMaxflow(0, 1));
        }
        return 0;
    }
    View Code
  • 相关阅读:
    [如何构建自己的轮式移动机器人系统·从入门到放弃]机器人底层篇
    Readme.txt
    [MATLAB&SIMULINK] 如何提取并处理Simscape Power System 中powergui的谐波分析数据
    记录2016年12月11日
    [深度强化学习] blog翻译使用Keras与Gym仿真环境进行深度Q学习(DQL)
    使用PARL与Gym仿真环境进行深度Q学习(DQL)
    Telerik控件使用Expression_DarkTheme后引发Combobx下拉问题
    [Win系统][临时方案]系统任务管理器不能使用临时性解决方案
    [Visual Studio]重置开发环境
    WPF中使用DataGrid后,里面的Button的Command不响应的问题
  • 原文地址:https://www.cnblogs.com/qwertiLH/p/8277767.html
Copyright © 2020-2023  润新知