zoukankan      html  css  js  c++  java
  • [网络流24题]数字梯形问题

    Description

    给定一个由$n$行数字组成的数字梯形如下图所示。梯形的第一行有$m$个数字。从梯形的顶部的$m$个数字开始,在每个数字处可以沿左下或右下方向移动,形成一条从梯形的顶至底的路径。
    规则$1$:从梯形的顶至底的$m$条路径互不相交。
    规则$2$:从梯形的顶至底的$m$条路径仅在数字结点处相交。
    规则$3$:从梯形的顶至底的$m$条路径允许在数字结点相交或边相交。

       image

    对于给定的数字梯形,分别按照规则$1$,规则$2$,和规则$3$计算出从梯形的顶至底的$m$条路径,使这$m$条路径经过的数字总和最大。

    Input

    第$1$行中有$2$个正整数$m,n$,分别表示数字梯形的第一行有$m$个数字,共有$n$行。

    接下来的$n$行是数字梯形中各行的数字$a_{i,j}$。第$i$行有$m+i-1$个数字。

    Output

    $3$行,每行$1$个整数,分别表示按照规则$1$,规则$2$,和规则$3$计算出的最大数字总和。

    Sample Input

    2 5
    2 3
    3 4 5
    9 10 9 1
    1 1 10 1 1
    1 1 10 12 1 1

    Sample Output

    66
    75
    77

    HINT

    $m,n;leq;20$

    Solution

    • 规则$1$:

    将每个点拆成$x_{i,j},y_{i,j}$. (限制点流量)

    从$s$向梯形顶层每个$x_{i,j}$连一条容量为$1$,费用为$0$的有向边,

    从梯形底层每个$y_{i,j}$向$t$连一条容量为$1$,费用为$0$的有向边,

    从$x_{i,j}$向$y_{i,j}$连一条容量为$1$,费用为$a_{i,j}$的有向边,

    从$y_{i,j}$向$x_{i+1,j},x_{i+1,j+1}$连一条容量为$1$,费用为$0$的有向边.

    求最大费用最大流.

    • 规则$2$:

    从$s$向梯形顶层每个$x_{i,j}$连一条容量为$1$,费用为$0$的有向边,

    从梯形底层每个$x_{i,j}$向$t$连一条容量为$+infty$,费用为$a_{i,j}$的有向边,

    从$x_{i,j}$向$x_{i+1,j},x_{i+1,j+1}$连一条容量为$1$,费用为$a_{i,j}$的有向边.(限制边流量)

    求最大费用最大流.

    • 规则$3$:

    从$s$向梯形顶层每个$x_{i,j}$连一条容量为$1$,费用为$0$的有向边,

    从梯形底层每个$x_{i,j}$向$t$连一条容量为$+infty$,费用为$a_{i,j}$的有向边,

    从$x_{i,j}$向$x_{i+1,j},x_{i+1,j+1}$连一条容量为$+infty$,费用为$a_{i,j}$的有向边.

    求最大费用最大流.

    #include<cmath>
    #include<ctime>
    #include<queue>
    #include<stack>
    #include<cstdio>
    #include<vector>
    #include<cstring>
    #include<cstdlib>
    #include<iostream>
    #include<algorithm>
    #define N 25
    #define M 45
    #define V 600
    #define E 2000
    #define INF 1000000000
    using namespace std;
    struct graph{
        int nxt,to,f,w;
    }e[E];
    struct edge{
        int e,v;
    }pre[E];
    int a[N][M],b[N][M],g[V],dis[V],n,m,s,t,cnt;
    bool inq[V];
    queue<int> q; 
    inline void addedge(int x,int y,int f,int w){
        e[++cnt].nxt=g[x];g[x]=cnt;
        e[cnt].to=y;e[cnt].f=f;e[cnt].w=w;
    }
    inline void adde(int x,int y,int f,int w){
        addedge(x,y,f,w);addedge(y,x,0,-w);
    }
    inline bool spfa(int u){
        for(int i=0;i<(t<<1);++i){
            dis[i]=-INF;inq[i]=false;
        }
        q.push(u);dis[u]=0;inq[u]=true;
        while(!q.empty()){
            u=q.front();q.pop();inq[u]=false;
            for(int i=g[u];i;i=e[i].nxt){
                if(e[i].f>0&&dis[u]+e[i].w>dis[e[i].to]){
                    dis[e[i].to]=dis[u]+e[i].w;
                    pre[e[i].to].e=i;pre[e[i].to].v=u;
                    if(!inq[e[i].to]){
                        inq[e[i].to]=true;q.push(e[i].to);
                    }
                }
            }
        }
        return dis[t]>-INF;
    }
    inline int mf(){
        int ret=0,d;
        while(true){
            if(!spfa(s)) return ret;
            d=INF;
            for(int i=t;i!=s;i=pre[i].v){
                d=min(d,e[pre[i].e].f);
            }
            ret+=d*dis[t];
            for(int i=t;i!=s;i=pre[i].v){
                e[pre[i].e].f-=d;e[pre[i].e^1].f+=d;
            }
        }
    }
    inline void Aireen(){
        scanf("%d%d",&m,&n);
        for(int i=1;i<=n;++i)
            for(int j=1;j<i+m;++j){
                b[i][j]=++cnt;
                scanf("%d",&a[i][j]);
            }
        s=0;t=cnt+1;
        //(1)
        s=0;t=cnt+1;cnt=1;
        for(int i=1;i<=n;++i)
            for(int j=1;j<i+m;++j)
                adde(b[i][j],b[i][j]+t,1,a[i][j]);
        for(int i=1;i<=m;++i)
            adde(s,b[1][i],1,0);
        for(int i=1;i<n+m;++i)
            adde(b[n][i]+t,t,1,0);
        for(int i=1;i<n;++i)
            for(int j=1;j<i+m;++j){
                adde(b[i][j]+t,b[i+1][j],1,0);
                adde(b[i][j]+t,b[i+1][j+1],1,0);
            }
        printf("%d
    ",mf());
        //(2)
        cnt=1;memset(g,0,sizeof(g));
        for(int i=1;i<=m;++i)
            adde(s,b[1][i],1,0);
        for(int i=1;i<n+m;++i)
            adde(b[n][i],t,INF,a[n][i]);
        for(int i=1;i<n;++i)
            for(int j=1;j<i+m;++j){
                adde(b[i][j],b[i+1][j],1,a[i][j]);
                adde(b[i][j],b[i+1][j+1],1,a[i][j]);
            }
        printf("%d
    ",mf());
        //(3)
        cnt=1;memset(g,0,sizeof(g));
        for(int i=1;i<=m;++i)
            adde(s,b[1][i],1,0);
        for(int i=1;i<n+m;++i)
            adde(b[n][i],t,INF,a[n][i]);
        for(int i=1;i<n;++i)
            for(int j=1;j<i+m;++j){
                adde(b[i][j],b[i+1][j],INF,a[i][j]);
                adde(b[i][j],b[i+1][j+1],INF,a[i][j]);
            }
        printf("%d
    ",mf());
    }
    int main(){
        freopen("digit.in","r",stdin);
        freopen("digit.out","w",stdout);
        Aireen();
        fclose(stdin);
        fclose(stdout);
        return 0;
    }
  • 相关阅读:
    回调函数 协程
    网络编程 之线程
    并发编程 之进程相关
    并发编程的理论 python中实现多进程
    基于tcp的粘包处理终极版本
    基于socket的网络编程
    数据分析
    zabbix从入门到放弃
    Linux
    Django
  • 原文地址:https://www.cnblogs.com/AireenYe/p/6243427.html
Copyright © 2011-2022 走看看