• HIT暑期集训 网络流


    最大流模板(修改版)

    /*网络流中的最大流问题
    即,给出一个图,图中每条边有一个容量,图中有两点分别为源点和汇点 
    在每条边流量不超过其容量的情况下,求解从原点开始能流到汇点的最大流量
    dinic算法是一种基于增广路思想求解最大流的算法,其基本步骤为:
    1、在图中找到一条从源点到汇点的路径,
    使路径上每条边的残余流量re大于零,称这条路径为增广路。
    2、取该路径上的最小re,记为re_min,并将答案max_flow加上re_min。
    将这条路径上所有边的re都减去re_min,他们的反向边都加上re_min。 
    不停进行以上两个步骤直至图中没有增广路,最后得到的max_flow就是最大流。
    下面是应用dinic算法求解最大流的代码。 
    */ 
    #include<cstdio>
    #include<cstring>
    #include<queue>
    #include<cmath>
    #define maxn 10005
    #define maxm 100005
    using namespace std; 
    const int inf=1<<30;
    int num,lst[maxn],cur[maxn],dep[maxn];
    int s,t,n,m;
    queue<int>q;
    struct in
    {
        int to,nxt,re;
    }e[maxm];
    void add(int x,int y,int z)//邻接表建图 
    {
        e[++num].to=y;
        e[num].nxt=lst[x];
        lst[x]=num;
        e[num].re=z;
    }
    void clear()
    {
        num=-1;//从0开始为边编号 
        memset(lst,-1,sizeof(lst));
    }
    int bfs()//广搜,进行图分层 
    {
        int i,u,v;
        while (!q.empty()) q.pop(); //清空队列 
        memset(dep,-1,sizeof(dep));
        dep[s]=0;
        q.push(s);
        while(!q.empty())
        {
            u=q.front();
            q.pop();
            for(i=lst[u];i!=-1;i=e[i].nxt)
            {
                v=e[i].to;
                if (e[i].re && dep[v]==-1)//如果该节点之前没有被搜索到并且不是反向边 
                {
                    dep[v]=dep[u]+1;//更新该节点深度 
                    q.push(v);//将该节点加入队列 
                }
            }
        }
        return dep[t]!=-1;//没有搜索到汇点就不存在增广路 
    }
    int dfs(int u,int flow)//寻找增广路并返回其流量 
    {
        //x表示当前节点,flow表示当前流到x的残量
        if (u==t || !flow) return flow;
        int i,v,res,used=0;//used表示u节点总共流出的流量 
        for (i=cur[u];i!=-1;i=e[i].nxt)
        {
            v=e[i].to;
            cur[u]=i;//当前弧优化  
            if (dep[v]==dep[u]+1 && e[i].re)//v为u的下一层,且当前边有残量>0 
            {
                res=dfs(v,min(flow,e[i].re));//res表示当前边流出的流量 
                if (res)
                {
                    used+=res;
                    flow-=res;
                    e[i].re-=res;
                    e[i^1].re+=res;//i^1是i的反向边  
                    if (!flow) return used;//流入当前点的流量流完了,退出 
                } 
            }
        }
        if (flow) dep[u]=-1;//优化,流到u的流量会有冗余,这一轮dfs中就再也用不到u了(u已经无法流出更多流量) 
        return used;
    }
    int dinic()//不停寻找增广路并更新答案,直至图中不存在增广路 
    {
        int i,maxflow=0;
        while (bfs())
        {
            for (i=0;i<=max(n,t);i++) cur[i]=lst[i];//当前弧优化,重置cur 
            maxflow+=dfs(s,inf);//加入寻找到的增广路的流量 
        }
        return maxflow;
    }
    int main()
    {
        int u,v,w,i;
        clear();
        scanf("%d%d%d%d",&n,&m,&s,&t);//n节点数,m边数,s源点,t汇点 
        for(i=1;i<=m;i++)//读入m条边 
        {
            scanf("%d%d%d",&u,&v,&w);
            add(u,v,w);
            add(v,u,0);//反向边 
        }
        printf("%d
    ",dinic());
        return 0;
    }
    dinic最大流模板,带注释
    #include<cstdio>
    #include<cstring>
    #include<queue>
    #include<cmath>
    #define maxn 10005
    #define maxm 100005
    using namespace std; 
    const int inf=1<<30;
    int num,lst[maxn],cur[maxn],dep[maxn];
    int s,t,n,m;
    queue<int>q;
    struct in
    {
        int to,nxt,re;
    }e[maxm];
    void add(int x,int y,int z)
    {
        e[++num].to=y;
        e[num].nxt=lst[x];
        lst[x]=num;
        e[num].re=z;
    }
    void clear()
    {
        num=-1;
        memset(lst,-1,sizeof(lst));
    }
    int bfs()
    {
        int i,u,v;
        while (!q.empty()) q.pop();
        memset(dep,-1,sizeof(dep));
        dep[s]=0;
        q.push(s);
        while(!q.empty())
        {
            u=q.front();
            q.pop();
            for(i=lst[u];i!=-1;i=e[i].nxt)
            {
                v=e[i].to;
                if (e[i].re && dep[v]==-1)
                {
                    dep[v]=dep[u]+1;
                    q.push(v);
                }
            }
        }
        return dep[t]!=-1;
    }
    int dfs(int u,int flow)
    {
        if (u==t || !flow) return flow;
        int i,v,res,used=0;
        for (i=cur[u];i!=-1;i=e[i].nxt)
        {
            v=e[i].to;
            cur[u]=i;
            if (dep[v]==dep[u]+1 && e[i].re)
            {
                res=dfs(v,min(flow,e[i].re));
                if (res)
                {
                    used+=res;
                    flow-=res;
                    e[i].re-=res;
                    e[i^1].re+=res;
                    if (!flow) return used;
                } 
            }
        }
        if (flow) dep[u]=-1; 
        return used;
    }
    int dinic()
    {
        int i,maxflow=0;
        while (bfs())
        {
            for (i=0;i<=max(n,t);i++) cur[i]=lst[i];
            maxflow+=dfs(s,inf);
        }
        return maxflow;
    }
    int main()
    {
        int u,v,w,i;
        clear();
        scanf("%d%d%d%d",&n,&m,&s,&t);
        for(i=1;i<=m;i++)
        {
            scanf("%d%d%d",&u,&v,&w);
            add(u,v,w);
            add(v,u,0); 
        }
        printf("%d
    ",dinic());
        return 0;
    }
    dinic最大流模板,无注释

    最大流最小费模板(修改spfa函数中的赋初值dis[i]=-inf与if (dis[v]<dis[u]+e[i].w)就可变为最大费用最大流。)

    #include<cstdio>
    #include<cstring>
    #include<queue>
    #include<cmath>
    #define maxn 10000
    #define maxm 40000
    using namespace std; 
    const int inf=1<<30;
    int num,lst[maxn];
    int pre[maxn],vis[maxn],flow[maxn],dis[maxn],from[maxn];
    int tot1,tot2,q1[maxn][2],q2[maxn][2];
    int s,t,n,m,lim;
    queue<int>q;
    struct in
    {
        int to,nxt,re,w;
    }e[maxm];
    void add(int x,int y,int z,int w)
    {
        e[++num].to=y;e[num].nxt=lst[x];lst[x]=num;e[num].re=z;e[num].w=w;
    }
    void clear()
    {
        num=-1;
        memset(lst,-1,sizeof(lst));
    }
    int spfa()
    {
        int i,u,v;
        while (!q.empty()) q.pop();
        for (i=1;i<=t;++i) 
        {
            pre[i]=-1;
            from[i]=-1;
            dis[i]=inf;
            vis[i]=0;
        }
        q.push(s);
        dis[s]=0;
        flow[s]=inf;
        vis[s]=1;
        while (!q.empty())
        {
            u=q.front();
            q.pop();
            vis[u]=0;
            for (i=lst[u];i!=-1;i=e[i].nxt)
            {
                v=e[i].to;
                if (!e[i].re) continue;
                if (dis[v]>dis[u]+e[i].w)
                {
                    dis[v]=dis[u]+e[i].w;
                    flow[v]=min(e[i].re,flow[u]);
                    pre[v]=i;
                    from[v]=u;
                    if (!vis[v]) 
                    {
                        vis[v]=1;
                        q.push(v);
                    }
                }
            }
        }
        return pre[t]!=-1;
    }
    int mfmv()
    {
        int mincost=0,maxflow=0,v;
        while (spfa())
        {
            mincost+=flow[t]*dis[t];
            maxflow+=flow[t];
            v=t;
            while (v!=s)
            {
                e[pre[v]].re-=flow[t];
                e[pre[v]^1].re+=flow[t];
                v=from[v];
            }
        }
        return mincost;
    }
    int main()
    {
        int i,x,y,z,w;
        clear();
        scanf("%d%d%d%d",&n,&m,&s,&t);
        for (i=1;i<=m;i++)
        {
            scanf("%d%d%d%d",&x,&y,&z,&w);
            add(x,y,z,w);
            add(y,x,0,-w);
        }
        printf("%d
    ",mfmv());
        return 0;
    } 
    mfmv模板,spfa,无注释

    B    HDU 3572

    建图,将每一天j与源点s连边add(s,j,m),每个任务i与汇点t连边add(i,t,p),每个任务i与可以做这个任务的每一天j连边add(j,i,1)。然后求最大流,如果最大流等于所有任务所需的天数p之和,就YES,否则NO。

    昨天折腾一晚上,不停TLE,然后加了一个优化(就是那个if (flow) dep[u]=-1的优化)过了。。行吧,修改了一下dinic模板。。

    #include<cstdio>
    #include<cstring>
    #include<queue>
    #include<cmath>
    #define maxn 1010
    #define maxm 500005
    #define inf 0x3f3f3f3f
    using namespace std; 
    int num,lst[maxn],dep[maxn],mark[maxn],cur[maxn];
    int s,t,n;
    queue<int>q;
    struct in
    {
        int to,nxt,re;
    }e[maxm];
    void add(int x,int y,int z)
    {
        e[++num].to=y;e[num].nxt=lst[x];lst[x]=num;e[num].re=z;
        e[++num].to=x;e[num].nxt=lst[y];lst[y]=num;e[num].re=0;
    }
    void clear()
    {
        num=-1;//从0开始为边编号 
        memset(lst,-1,sizeof(lst));
    }
    int bfs()//广搜,进行图分层 
    {
        int i,u,v;
        while (!q.empty()) q.pop(); //清空队列 
        memset(dep,-1,sizeof(dep));
        dep[s]=0;
        q.push(s);
        while(!q.empty())
        {
            u=q.front();
            q.pop();
            for(i=lst[u];i!=-1;i=e[i].nxt)
            {
                v=e[i].to;
                if (e[i].re && dep[v]==-1)//如果该节点之前没有被搜索到并且不是反向边 
                {
                    dep[v]=dep[u]+1;//更新该节点深度 
                    q.push(v);//将该节点加入队列 
                }
            }
        }
        return dep[t]!=-1;//没有搜索到汇点就不存在增广路 
    }
    int dfs(int u,int flow)//寻找增广路并返回其流量 
    {
        //x表示当前节点,flow表示当前流到x的残量
        if (u==t || !flow) return flow;
        int i,v,res,used=0;//used表示u节点总共流出的流量 
        for (i=cur[u];i!=-1;i=e[i].nxt)
        {
            v=e[i].to;
            cur[u]=i;//当前弧优化  
            if (dep[v]==dep[u]+1 && e[i].re)//v为u的下一层,且当前边有残量>0 
            {
                res=dfs(v,min(flow,e[i].re));//res表示当前边流出的流量 
                if (res)
                {
                    used+=res;
                    flow-=res;
                    e[i].re-=res;
                    e[i^1].re+=res;//i^1是i的反向边  
                    if (!flow) return used;//流入当前点的流量流完了,退出 
                } 
            }
        }
        if (flow) dep[u]=-1;//优化,流到u的流量会有冗余,这一轮dfs中就再也用不到u了(u已经无法流出更多流量) 
        return used;
    }
    int dinic()//不停寻找增广路并更新答案,直至图中不存在增广路 
    {
        int i,maxflow=0;
        while (bfs())
        {
            for (i=0;i<=max(n,t);i++) cur[i]=lst[i];//当前弧优化,重置cur 
            maxflow+=dfs(s,inf);//加入寻找到的增广路的流量 
        }
        return maxflow;
    }
    int main()
    {
        int i,j,k,x,y,z,T,m,sum,note=1;
        int maxflow,flow;
        scanf("%d",&T);
        for (k=1;k<=T;k++)
        {
            scanf("%d%d",&n,&m);
            s=0;t=500+n+1;
            clear();
            sum=0;
            memset(mark,0,sizeof(mark));
            for (i=1;i<=n;i++)
            {
                scanf("%d%d%d",&x,&y,&z);
                for (j=y;j<=z;j++)
                {
                    mark[j]=1;
                    add(j,i+500,1);
                }
                add(i+500,t,x);
                sum+=x;
            }
            for (i=1;i<=500;i++)
            {
                if (!mark[i]) continue;
                add(s,i,m);
            }
            if (dinic()==sum) printf("Case %d: Yes
    
    ",k);
            else printf("Case %d: No
    
    ",k);
        }
        return 0;
     }
    View Code
  • 相关阅读:
    FORM内置系统变量
    linux简单命常用令
    详解EBS接口开发之库存事务处理-物料批次导入
    TRIZ系列-创新原理-5-合并原理
    《Master Opencv...读书笔记》非刚性人脸跟踪 IV (终)
    Echarts折线图
    Redis命令学习-SortedSet(有序集合)
    tky项目第③个半月总结
    Torrent 文件图文解析
    ofbiz SSO 单点登录
  • 原文地址:https://www.cnblogs.com/lsykk/p/13499958.html
Copyright © 2020-2023  润新知