网络流24题-数字梯形问题

数字梯形问题

 

题目描述

给定一个由 n 行数字组成的数字梯形如下图所示。

梯形的第一行有 m 个数字。从梯形的顶部的 m 个数字开始,在每个数字处可以沿左下或右下方向移动,形成一条从梯形的顶至底的路径。

分别遵守以下规则:

  1. 从梯形的顶至底的 m 条路径互不相交;

  2. 从梯形的顶至底的 m 条路径仅在数字结点处相交;

  3. 从梯形的顶至底的 m 条路径允许在数字结点相交或边相交。

输入输出格式

输入格式:

第 1 行中有 2 个正整数 m 和 n ,分别表示数字梯形的第一行有 m 个数字,共有 n 行。接下来的 n 行是数字梯形中各行的数字。

第 1 行有 m 个数字,第 2 行有 m+1 个数字,以此类推。

输出格式:

将按照规则 1 ,规则 2 ,和规则 3 计算出的最大数字总和并输出,每行一个最大总和。

输入输出样例

输入样例: 
2 5
2 3
3 4 5
9 10 9 1
1 1 10 1 1
1 1 10 12 1 1
输出样例: 
66
75
77

说明

1m,n20


费用流。
找好约束条件是在点上还是边上就好了。
#include<bits/stdc++.h>
#define INF LLONG_MAX/2
#define N 1250
using namespace std;

typedef struct
{
    int u,v;
    long long flow,cost;
}ss;

ss edg[N*N];
vector<int>edges[N];
int now_edges=0;

void addedge(int u,int v,long long flow,long long cost)
{
    cost*=-1;
    edges[u].push_back(now_edges);
    edg[now_edges++]=(ss){u,v,flow,cost};
    edges[v].push_back(now_edges);
    edg[now_edges++]=(ss){v,u,0,-cost};
}

bool spfa(int s,int t,long long &flow,long long &cost)
{
//    printf("%lld %lld
",flow,cost);
    long long dis[N];
    for(int i=0;i<N;i++)dis[i]=INF;
    dis[s]=0;
    long long maxflow[N];
    maxflow[s]=INF;
    int pre[N]={0};
    int vis[N]={0};
    vis[s]=1;
    
    queue<int>q;
    q.push(s);
    
    while(!q.empty())
    {
        int now=q.front();
        q.pop();
        vis[now]=0;
        
        int Size=edges[now].size();
        
        for(int i=0;i<Size;i++)
        {
            ss e=edg[edges[now][i]];
            if(e.flow>0&&dis[e.v]>dis[now]+e.cost)
            {
                dis[e.v]=dis[now]+e.cost;
                pre[e.v]=edges[now][i];
                maxflow[e.v]=min(maxflow[now],e.flow);
                
                if(!vis[e.v])
                {
                    q.push(e.v);
                    vis[e.v]=1;
                }

            }

        }
        
    }
    
    if(dis[t]==INF)return false;
    
    flow+=maxflow[t];
    cost+=maxflow[t]*dis[t];
    
    int now=t;
    while(now!=s)
    {
        edg[pre[now]].flow-=maxflow[t];
        edg[pre[now]^1].flow+=maxflow[t];
        now=edg[pre[now]].u;
    }

    return true;
}

void f(int s,int t,long long &flow,long long &cost)
{
    while(spfa(s,t,flow,cost));
}

void init()
{
    for(int i=0;i<N;i++)edges[i].clear();
    now_edges=0;
}

long long Map[25][25];
int x[25][25],y[25][25];

int main()
{
    int m,n,cut=1,s,t;
    scanf("%d %d",&m,&n);
    for(int i=1;i<=n;i++)
    for(int j=1;j<=m+i-1;j++)
    {
        scanf("%lld",&Map[i][j]);
        x[i][j]=2*cut-1;
        y[i][j]=2*cut;
        cut++;
    }
    
    s=2*cut+1;
    t=2*cut+2;
    
    long long flow=0,cost=0;
    init();
    
    for(int i=1;i<=m;i++)addedge(s,x[1][i],1,0);
    for(int i=1;i<=m+n-1;i++)addedge(y[n][i],t,1,0);
    
    for(int i=1;i<n;i++)
    for(int j=1;j<=m+i-1;j++)
    {
        addedge(y[i][j],x[i+1][j],1,0);
        addedge(y[i][j],x[i+1][j+1],1,0);
    }
    
    for(int i=1;i<=n;i++)
    for(int j=1;j<=m+i-1;j++)addedge(x[i][j],y[i][j],1,Map[i][j]);
    
    f(s,t,flow,cost);
    printf("%lld
",-cost);
    
    flow=0;
    cost=0;
    init();

    for(int i=1;i<=m;i++)addedge(s,x[1][i],1,0);
    for(int i=1;i<=m+n-1;i++)addedge(y[n][i],t,INF,0);

    for(int i=1;i<n;i++)
    for(int j=1;j<=m+i-1;j++)
    {
        addedge(y[i][j],x[i+1][j],1,0);
        addedge(y[i][j],x[i+1][j+1],1,0);
    }

    for(int i=1;i<=n;i++)
    for(int j=1;j<=m+i-1;j++)addedge(x[i][j],y[i][j],INF,Map[i][j]);

    f(s,t,flow,cost);
    printf("%lld
",-cost);
    
    flow=0;
    cost=0;
    init();

    for(int i=1;i<=m;i++)addedge(s,x[1][i],1,0);
    for(int i=1;i<=m+n-1;i++)addedge(y[n][i],t,INF,0);

    for(int i=1;i<n;i++)
    for(int j=1;j<=m+i-1;j++)
    {
        addedge(y[i][j],x[i+1][j],INF,0);
        addedge(y[i][j],x[i+1][j+1],INF,0);
    }

    for(int i=1;i<=n;i++)
    for(int j=1;j<=m+i-1;j++)addedge(x[i][j],y[i][j],INF,Map[i][j]);

    f(s,t,flow,cost);
    printf("%lld
",-cost);
    
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/tian-luo/p/9539753.html