[网络流24题]数字梯形问题
Description
给定一个由$n$行数字组成的数字梯形如下图所示。梯形的第一行有$m$个数字。从梯形的顶部的$m$个数字开始,在每个数字处可以沿左下或右下方向移动,形成一条从梯形的顶至底的路径。
规则$1$:从梯形的顶至底的$m$条路径互不相交。
规则$2$:从梯形的顶至底的$m$条路径仅在数字结点处相交。
规则$3$:从梯形的顶至底的$m$条路径允许在数字结点相交或边相交。
对于给定的数字梯形,分别按照规则$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\n",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\n",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\n",mf()); } int main(){ freopen("digit.in","r",stdin); freopen("digit.out","w",stdout); Aireen(); fclose(stdin); fclose(stdout); return 0; }