zoukankan      html  css  js  c++  java
  • 菜鸟物流的运输网络(网络流)

    题目链接

    比赛时用dp想了两个小时。。

    看了题解说是网络流,感觉被打脸。

    知道了这个模型之后,这题就是套个模板直接水过的了。

    先拆点限流,把mid当源点,然后把a做汇点跑一次网络流,再把b做汇点跑一次网络流。 mdwzszz

    (第一次网络流,分两次跑)

    code:

    //
    //  main.cpp
    //  jisuanke11215
    //
    //  Created by New_Life on 16/7/4.
    //  Copyright © 2016年 chenhuan001. All rights reserved.
    //
    
    //网络流,教育了我
    #include <iostream>
    #include <stdio.h>
    #include <string.h>
    #include <algorithm>
    using namespace std;
    //网络流SAP模板,复杂度O(N^2*M)
    //使用前调用init(源点,汇点,图中点的个数),然后调用add_edge()加边
    //调用getflow得出最大流
    #define N 220
    #define M N*N
    #define INF 0x3fffff
    
    
    struct Max_Flow
    {
        struct node
        {
            int to,w,next;
        }edge[M];
        
        int s,t;
        int nn;
        int cnt,pre[N];
        int lv[N],gap[N];
        
        void init(int ss,int tt,int num)
        {
    //        s=ss;
    //        t=tt;
            nn = num;//
            cnt=0;
            memset(pre,-1,sizeof(pre));
        }
        void add_edge(int u,int v,int w)//同时建两条边
        {
            edge[cnt].to=v;
            edge[cnt].w=w;
            edge[cnt].next=pre[u];
            pre[u]=cnt++;
            
            edge[cnt].to=u;
            edge[cnt].w=0;
            edge[cnt].next=pre[v];
            pre[v]=cnt++;
        }
        
        int sdfs(int k,int w)
        {
            if(k==t) return w;
            int f=0;
            int mi=nn-1;
            for(int p=pre[k];p!=-1;p=edge[p].next)
            {
                int v=edge[p].to,tw=edge[p].w;
                if(tw!=0)
                {
                    if(lv[k]==lv[v]+1)
                    {
                        int tmp=sdfs(v,min(tw,w-f));
                        f+=tmp;
                        edge[p].w-=tmp;
                        edge[p^1].w+=tmp;
                        if(f==w||lv[s]==nn) break;
                    }
                    if(lv[v]<mi) mi=lv[v];
                }
            }
            if(f==0)
            {
                gap[lv[k]]--;
                if( gap[ lv[k] ]==0 )
                {
                    lv[s]=nn;
                }
                lv[k]=mi+1;
                gap[lv[k]]++;
            }
            return f;
        }
        
        int getflow()
        {
            int sum=0;
            memset(lv,0,sizeof(lv));
            memset(gap,0,sizeof(gap));
            gap[0]=nn;
            while(lv[s]<nn)
            {
                sum+=sdfs(s,INF);
            }
            return sum;
        }
        
    }mxf;
    
    int mat[110][110];
    
    int main(int argc, const char * argv[]) {
        int T;
        cin>>T;
        while(T--)
        {
            int n,m;
            cin>>n>>m;
            int a,b,mid;
            cin>>a>>b>>mid;
            memset(mat,0,sizeof(mat));
            for(int i=0;i<m;i++)
            {
                int u,v;
                cin>>u>>v;
                mat[u][v] = mat[v][u] = 1;
            }
            //然后就就构建网络流
            mxf.init(0, 0, 2*n+2);
            for(int i=1;i<=n;i++)
            {
                if(i!=mid)
                    mxf.add_edge(2*i, 2*i+1, 1);
                for(int j=i+1;j<=n;j++)
                {
                    if(mat[i][j] == 0) continue;
                    if(j!=mid)
                        mxf.add_edge(2*i+1, 2*j, 10);
                    
                    if(i!=mid)
                        mxf.add_edge(2*j+1, 2*i, 10);
                }
            }
            mxf.s = 2*mid+1;
            mxf.t = 2*a+1;
            mxf.getflow();
            
            mxf.t = 2*b+1;
            mxf.getflow();
            //找到两次流之后,就是求路径了
            int ans[110];
            int anscnt=0;
            int pp = a;
            while(pp!=mid)
            {
                printf("%d ",pp);
                for(int p=mxf.pre[2*pp];p!=-1;p=mxf.edge[p].next)
                {
                    int v = mxf.edge[p].to;
                    if(mxf.edge[p].w == 0) continue;
                    pp = v/2; break;
                }
            }
            printf("%d",mid);
            pp = b;
            
            while(pp!=mid)
            {
                ans[anscnt++] = pp;
                for(int p=mxf.pre[2*pp];p!=-1;p=mxf.edge[p].next)
                {
                    int v = mxf.edge[p].to;
                    if(mxf.edge[p].w == 0) continue;
                    pp = v/2; break;
                }
            }
            for(int i=anscnt-1;i>=0;i--)
                printf(" %d",ans[i]);
            printf("
    ");
        }
        return 0;
    }
    /**
     1
     5 5
     2 4 3
     1 2
     2 3
     3 4
     4 5
     5 1
     
    */
  • 相关阅读:
    TCP/IP详解学习笔记
    C++知识库
    C++中基类的析构函数为什么要用virtual虚析构函数
    秒杀多线程面试题系列
    很详细全部的WinDbg学习资料
    Ubuntu中libprotobuf版本冲突的解决方案
    Windows系统中内存泄露与检测工具及方法
    Ubuntu脚本修改IP信息
    【Qt】Qt Quick 之 QML 与 C++ 混合编程详解
    分布式系统消息中间件——RabbitMQ的使用基础篇
  • 原文地址:https://www.cnblogs.com/chenhuan001/p/5640152.html
Copyright © 2011-2022 走看看