Description
给定一个由n 行数字组成的数字梯形如下图所示。梯形的第一行有m 个数字。从梯形的顶部的m 个数字开始,在每个数字处可以沿左下或右下方向移动,形成一条从梯形的顶至底的路径。
规则1:从梯形的顶至底的m条路径互不相交。
规则2:从梯形的顶至底的m条路径仅在数字结点处相交。
规则3:从梯形的顶至底的m条路径允许在数字结点相交或边相交。
对于给定的数字梯形,分别按照规则1,规则2,和规则3 计算出从梯形的顶至底的m条路径,使这m条路径经过的数字总和最大。
Input
第1 行中有2个正整数m和n(m,n<=20),分别表示数字梯形的第一行有m个数字,共有n 行。
接下来的n 行是数字梯形中各行的数字。第1 行有m个数字,第2 行有m+1 个数字,…。
Output
将按照规则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
将每个点一分为二,这个点的上的值赋给连接这两个的边的费用,其他边按照题目的要求来连,费用都为0。
题目有三问,就跑三遍最大费用最大流。
第一问:每条边的容量都为1。
第二问:拆开的两个点之间的容量为正无穷,与汇点的容量为正无穷。
第三问:除了源点之外其他边的容量都为正无穷。
(代码巨吃藕无比)
#include<set> #include<map> #include<queue> #include<stack> #include<ctime> #include<cmath> #include<string> #include<vector> #include<cstdio> #include<cstdlib> #include<cstring> #include<iostream> #include<algorithm> #define inf 1999999999 using namespace std; struct data{ int nex,to,w,c; }e[10000],g1[10000],g2[10000],g3[10000]; int a[30][30],head1[800],head2[800],head3[800],head[800],edge1=-1,edge2=-1,edge3=-1,dis[800],vis[800],pre[800]; void add1(int from,int to,int w,int c){ g1[++edge1].nex=head1[from]; g1[edge1].to=to,g1[edge1].w=w,g1[edge1].c=c; head1[from]=edge1; } void add2(int from,int to,int w,int c){ g2[++edge2].nex=head2[from]; g2[edge2].to=to,g2[edge2].w=w,g2[edge2].c=c; head2[from]=edge2; } void add3(int from,int to,int w,int c){ g3[++edge3].nex=head3[from]; g3[edge3].to=to,g3[edge3].w=w,g3[edge3].c=c; head3[from]=edge3; } bool SPFA(int s,int t){ queue<int>q; q.push(s); memset(dis,127,sizeof(dis)); memset(pre,0,sizeof(pre)); int zd=dis[0]; vis[s]=1;dis[s]=0; while(!q.empty()){ int u=q.front();q.pop(); vis[u]=0; for(int i=head[u];i!=-1;i=e[i].nex){ if(e[i].w>0 && dis[e[i].to]>dis[u]+e[i].c){ dis[e[i].to]=dis[u]+e[i].c; pre[e[i].to]=i; if(!vis[e[i].to]) vis[e[i].to]=1,q.push(e[i].to); } } } if(dis[t]==zd) return 0; else return 1; } int end(int s,int t){ int p=0,sum=1999999999,ans=0; for(int u=t;u!=s;u=e[p^1].to) p=pre[u],sum=min(sum,e[p].w); for(int u=t;u!=s;u=e[p^1].to){ p=pre[u]; e[p].w-=sum; e[p^1].w+=sum; ans+=sum*e[p].c; } return ans; } int solve(int s,int t){ int flow=0; while(SPFA(s,t)) flow+=end(s,t); return -flow; } int main() { freopen("!.in","r",stdin); freopen("!.out","w",stdout); memset(head,-1,sizeof(head)); memset(head1,-1,sizeof(head1)); memset(head2,-1,sizeof(head2)); memset(head3,-1,sizeof(head3)); int n,m;scanf("%d%d",&n,&m); int s=0,sum=(n+n+m-1)*m/2,t=(n+n+m-1)*m+1; for(int i=1;i<=m;i++) for(int j=1;j<n+i;j++){ scanf("%d",&a[i][j]); int s1=(n+n+i-2)*(i-1)/2+j; add1(s1,s1+sum,1,-a[i][j]),add1(s1+sum,s1,0,a[i][j]); add2(s1,s1+sum,inf,-a[i][j]),add2(s1+sum,s1,0,a[i][j]); add3(s1,s1+sum,inf,-a[i][j]),add3(s1+sum,s1,0,a[i][j]); } for(int i=1;i<=n;i++) add1(s,i,1,0),add1(i,s,0,0),add2(s,i,1,0),add2(i,s,0,0),add3(s,i,1,0),add3(i,s,0,0); for(int i=1;i<m;i++) for(int j=1;j<n+i;j++){ int s=(n+n+i-1)*i/2+j,s1=(n+n+i-2)*(i-1)/2+j; add1(s1+sum,s,1,0),add1(s,s1+sum,0,0); add1(s1+sum,s+1,1,0),add1(s+1,s1+sum,0,0); add2(s1+sum,s,1,0),add2(s,s1+sum,0,0); add2(s1+sum,s+1,1,0),add2(s+1,s1+sum,0,0); add3(s1+sum,s,inf,0),add3(s,s1+sum,0,0); add3(s1+sum,s+1,inf,0),add3(s+1,s1+sum,0,0); } for(int i=1;i<n+m;i++){ int s=(n+n+m-2)*(m-1)/2; add1(s+i+sum,t,1,0),add1(t,s+i+sum,0,0); add2(s+i+sum,t,inf,0),add2(t,s+i+sum,0,0); add3(s+i+sum,t,inf,0),add3(t,s+i+sum,0,0); } memcpy(e,g1,sizeof(e)); memcpy(head,head1,sizeof(head)); printf("%d ",solve(s,t)); memcpy(head,head2,sizeof(head)); memcpy(e,g2,sizeof(e)); printf("%d ",solve(s,t)); memcpy(head,head3,sizeof(head)); memcpy(e,g3,sizeof(e)); printf("%d ",solve(s,t)); }