zoukankan      html  css  js  c++  java
  • 网络流24题——数字梯形问题 luogu 4013

    题目描述:这里

    极其裸的一道费用流问题

    首先分析第一问,由于要求一个点只能经过一次,所以我们将梯形中的每一个点拆成两个点(记为入点和出点,顾名思义,入点用来承接上一行向这一行的边,出点用来向下一行连边)

    然后将出入点之间的流量设为1,边权设为0,这样就有效保证了一个点只经过一次

    接下来,我们从上一行的出点向下一行的入点连边,容量为1,费用为下一行对应点的代价的相反数,然后建起超级源点与超级终点,分别向第一行的入点连边,容量1费用0,由最后一行出点向终点连边,容量1费用0,跑一遍费用流即可(就是套路的最大费用流)

    然后看第二问,发现点可以重复经过,这样就不用拆点了,但边不能重复走,所以我们不拆点,剩下的建边与上面相同

    但是注意:两条路径可以相交于最后一行,这样的话如果最后一行的点向汇点连边的容量为1是不够的,所以设的容量要大于等于2

    第三问就是把除了源点到第一行的边以外的边边权全改为正无穷即可

    #include <cstdio>
    #include <cmath>
    #include <cstring>
    #include <cstdlib>
    #include <iostream>
    #include <algorithm>
    #include <queue>
    #include <stack>
    #define ll long long
    using namespace std;
    const ll inf=0x3f3f3f3f3f3f3f3fll;
    struct Edge
    {
        int next;
        int to;
        ll val;
        ll pri;
    }edge[10005];
    int head[1005];
    int nnum[55][55];
    ll a[55][55];
    ll dis[1005];
    int pre[1005];
    int fa[1005];
    ll lim[1005];
    bool used[1005];
    int cnt=1;
    int tot=0;
    int st,ed;
    int n,m;
    void init()
    {
        memset(edge,0,sizeof(edge));
        memset(head,-1,sizeof(head));
        cnt=1;
    }
    void add(int l,int r,ll w,ll v)
    {
        edge[cnt].next=head[l];
        edge[cnt].to=r;
        edge[cnt].val=w;
        edge[cnt].pri=v;
        head[l]=cnt++;
    }
    int ide(int x)
    {
        return (x&1)?x+1:x-1;
    }
    bool spfa()
    {
        memset(dis,0x3f,sizeof(dis));
        memset(lim,0,sizeof(lim));
        memset(used,0,sizeof(used));
        used[st]=1;
        lim[st]=inf;
        dis[st]=0;
        pre[ed]=-1;
        queue <int> M;
        M.push(st);
        while(!M.empty())
        {
            int u=M.front();
            M.pop();
            for(int i=head[u];i!=-1;i=edge[i].next)
            {
                int to=edge[i].to;
                if(edge[i].val&&dis[to]>dis[u]+edge[i].pri)
                {
                    dis[to]=dis[u]+edge[i].pri;
                    lim[to]=min(lim[u],edge[i].val);
                    pre[to]=i,fa[to]=u;
                    if(!used[to])used[to]=1,M.push(to);
                }
            }
            used[u]=0;
        }
        return pre[ed]!=-1;
    }
    ll EK()
    {
        ll maxw=0,minv=0;
        while(spfa())
        {
            maxw+=lim[ed];
            minv+=dis[ed]*lim[ed];
            int temp=ed;
            while(temp!=st)
            {
                edge[pre[temp]].val-=lim[ed];
                edge[ide(pre[temp])].val+=lim[ed];
                temp=fa[temp];
            }
        }
        return minv;
    }
    int main()
    {
        scanf("%d%d",&m,&n);
        init();
        st=0,ed=1;
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=m+i-1;j++)
            {
                scanf("%lld",&a[i][j]);
                nnum[i][j]=++tot;
            }
        }
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=m+i-1;j++)
            {
                add(nnum[i][j]<<1,(nnum[i][j]<<1)|1,1,-a[i][j]);
                add((nnum[i][j]<<1)|1,nnum[i][j]<<1,0,a[i][j]);
                if(i==1)
                {
                    add(st,nnum[i][j]<<1,1,0);
                    add(nnum[i][j]<<1,st,0,0);
                }
                if(i==n)
                {
                    add((nnum[i][j]<<1)|1,ed,1,0);
                    add(ed,(nnum[i][j]<<1)|1,0,0);
                }else
                {
                    add((nnum[i][j]<<1)|1,(nnum[i+1][j]<<1),1,0);
                    add((nnum[i+1][j]<<1),(nnum[i][j]<<1)|1,0,0);
                    add((nnum[i][j]<<1)|1,(nnum[i+1][j+1]<<1),1,0);
                    add((nnum[i+1][j+1]<<1),(nnum[i][j]<<1)|1,0,0);
                }
            }
        }
        printf("%lld
    ",-EK());
        init();
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=m+i-1;j++)
            {
                if(i==1)
                {
                    add(st,nnum[i][j]+1,1,-a[i][j]);
                    add(nnum[i][j]+1,st,0,a[i][j]);
                }
                if(i==n)
                {
                    add(nnum[i][j]+1,ed,2,0);
                    add(ed,nnum[i][j]+1,0,0);
                }else
                {
                    add(nnum[i][j]+1,nnum[i+1][j]+1,1,-a[i+1][j]);
                    add(nnum[i+1][j]+1,nnum[i][j]+1,0,a[i+1][j]);
                    add(nnum[i][j]+1,nnum[i+1][j+1]+1,1,-a[i+1][j+1]);
                    add(nnum[i+1][j+1]+1,nnum[i][j]+1,0,a[i+1][j+1]);
                }
            }
        }
        printf("%lld
    ",-EK());
        init();
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=m+i-1;j++)
            {
                if(i==1)
                {
                    add(st,nnum[i][j]+1,1,-a[i][j]);
                    add(nnum[i][j]+1,st,0,a[i][j]);
                }
                if(i==n)
                {
                    add(nnum[i][j]+1,ed,inf,0);
                    add(ed,nnum[i][j]+1,0,0);
                }else
                {
                    add(nnum[i][j]+1,nnum[i+1][j]+1,inf,-a[i+1][j]);
                    add(nnum[i+1][j]+1,nnum[i][j]+1,0,a[i+1][j]);
                    add(nnum[i][j]+1,nnum[i+1][j+1]+1,inf,-a[i+1][j+1]);
                    add(nnum[i+1][j+1]+1,nnum[i][j]+1,0,a[i+1][j+1]);
                }
            }
        }
        printf("%lld
    ",-EK());
        return 0;
    }
  • 相关阅读:
    git
    代理上网时git不能直接连接远程库的解决办法
    Python程序练习2--模拟三级菜单
    python os模块常用文件操作方法
    Python程序练习1-模拟用户登录验证
    牛牛牛图片胡乱下载
    oozie 4.1.0与4.2.0版本问题BUG
    hbase 协处理器,实现group by,distinct函数
    Js公共操作类 之 String 扩展方法介绍(一)
    CSS3之伪元素选择器和伪类选择器
  • 原文地址:https://www.cnblogs.com/zhangleo/p/10772737.html
Copyright © 2011-2022 走看看