【刷题】LOJ 6010 「网络流 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

数据范围与提示

\(1 \leq m, n \leq 20\)

题解

对于规则一,点和边都只能经过一次,那么拆点,之间连容量为 \(1\) 的边,点与点之间的边容量也为 \(1\)
对于规则二,即点可以经过多次,那么把拆点后之间的边的容量改为 \(inf\) 就可以了
对于规则三,在规则二的基础上,把点与点之间的边改为 \(inf\) 即可

#include<bits/stdc++.h>
#define ui unsigned int
#define ll long long
#define db double
#define ld long double
#define ull unsigned long long
const int MAXN=1200+10,MAXM=MAXN*MAXN+10,inf=0x3f3f3f3f;
int n,m,G[MAXN][MAXN],e,beg[MAXN],cur[MAXN],level[MAXN],p[MAXN],to[MAXM<<1],nex[MAXM<<1],cap[MAXM<<1],was[MAXM<<1],vis[MAXN],clk,s,t,all;
ll answas;
std::queue<int> q;
template<typename T> inline void read(T &x)
{
    T data=0,w=1;
    char ch=0;
    while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
    if(ch=='-')w=-1,ch=getchar();
    while(ch>='0'&&ch<='9')data=((T)data<<3)+((T)data<<1)+(ch^'0'),ch=getchar();
    x=data*w;
}
template<typename T> inline void write(T x,char ch='\0')
{
    if(x<0)putchar('-'),x=-x;
    if(x>9)write(x/10);
    putchar(x%10+'0');
    if(ch!='\0')putchar(ch);
}
template<typename T> inline void chkmin(T &x,T y){x=(y<x?y:x);}
template<typename T> inline void chkmax(T &x,T y){x=(y>x?y:x);}
template<typename T> inline T min(T x,T y){return x<y?x:y;}
template<typename T> inline T max(T x,T y){return x>y?x:y;}
inline int id(int x,int y)
{
    return (n+n+x-2)*(x-1)/2+y;
}
inline void insert(int x,int y,int z,int k)
{
    to[++e]=y;
    nex[e]=beg[x];
    beg[x]=e;
    cap[e]=z;
    was[e]=k;
    to[++e]=x;
    nex[e]=beg[y];
    beg[y]=e;
    cap[e]=0;
    was[e]=-k;
}
inline void build(int ft,int sd)
{
    e=1;memset(beg,0,sizeof(beg));answas=0;
    for(register int i=1;i<=n;++i)insert(s,id(1,i),1,-G[1][i]);
    for(register int i=1;i<=all;++i)insert(i,i+all,ft?inf:1,0);
    for(register int i=1;i<m;++i)
        for(register int j=1;j<=n+i-1;++j)
        {
            insert(id(i,j)+all,id(i+1,j),sd?inf:1,-G[i+1][j]);
            insert(id(i,j)+all,id(i+1,j+1),sd?inf:1,-G[i+1][j+1]);
        }
    for(register int i=1;i<=n+m-1;++i)insert(id(m,i)+all,t,ft||sd?inf:1,0);
}
inline bool bfs()
{
    memset(level,inf,sizeof(level));
    level[s]=0;
    p[s]=1;
    q.push(s);
    while(!q.empty())
    {
        int x=q.front();
        q.pop();
        p[x]=0;
        for(register int i=beg[x];i;i=nex[i])
            if(cap[i]&&level[to[i]]>level[x]+was[i])
            {
                level[to[i]]=level[x]+was[i];
                if(!p[to[i]])p[to[i]]=1,q.push(to[i]);
            }
    }
    return level[t]!=inf;
}
inline int dfs(int x,int maxflow)
{
    if(x==t||!maxflow)return maxflow;
    vis[x]=clk;
    int res=0;
    for(register int &i=cur[x];i;i=nex[i])
        if((vis[to[i]]^vis[x])&&cap[i]&&level[to[i]]==level[x]+was[i])
        {
            int f=dfs(to[i],min(maxflow,cap[i]));
            cap[i]-=f;
            cap[i^1]+=f;
            res+=f;
            answas+=1ll*f*was[i];
            maxflow-=f;
            if(!maxflow)break;
        }
    vis[x]=0;
    return res;
}
inline int MCMF()
{
    int res=0;
    while(bfs())clk++,memcpy(cur,beg,sizeof(cur)),res+=dfs(s,inf);
    return res;
}
int main()
{
    read(n);read(m);
    all=(n+n+m-1)*m/2,s=all+all+1,t=s+1;
    for(register int i=1;i<=m;++i)
        for(register int j=1;j<=n+i-1;++j)read(G[i][j]);
    build(0,0);MCMF();write(-answas,'\n');
    build(1,0);MCMF();write(-answas,'\n');
    build(1,1);MCMF();write(-answas,'\n');
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/hongyj/p/9432942.html